设计模式 java (讲述设计模式概要,适合初学者)
### 设计模式概要 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。设计模式大致可分为三类:创建型模式、结构型模式和行为型模式。 #### 一、策略模式(Strategy Pattern) 策略模式定义了一系列算法,并将每一个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。在这个例子中,通过刘备到江东的故事引入了策略模式的概念。 **类图**: - `IStrategy` 接口定义了一个操作的方法 `operate()`, 这个方法代表了不同的算法或策略。 - `BackDoor` 类实现了 `IStrategy` 接口,具体实现了策略,比如“找乔国老帮忙,使孙权不能杀刘备”。 **应用场景**: - 当多个类只区别在他们的行为上时。 - 当一个类的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时。 - 当你需要使用一个算法的不同变体时。 **优点**: - 多个策略可以共享相同的接口,这样它们可以互换使用。 - 客户端可以选择并使用不同的策略,而无需知道策略的具体实现细节。 **缺点**: - 如果策略数量较多,那么类的数量会增加很多。 - 客户端需要了解所有策略类才能选择合适的策略。 #### 二、代理模式(Proxy Pattern) 代理模式提供一个代理对象来控制对一个对象的访问。通常用于实现延迟加载、远程调用等场景。 **类图**: - `Subject` 接口定义了真实主题和代理主题共同的操作。 - `RealSubject` 实现了 `Subject` 接口,提供了真实的服务。 - `Proxy` 类也实现了 `Subject` 接口,并包含了一个指向 `RealSubject` 的引用。 **应用场景**: - 当直接访问某个对象会带来不便时。 - 当客户端需要访问一个远程的对象时。 - 当需要创建一个资源消耗较大的对象时。 **优点**: - 可以在不修改原接口的情况下增加额外的功能。 - 增强了控制力,可以对客户端隐藏真实主题。 **缺点**: - 代理模式会增加系统的复杂度。 - 对于某些类型的应用来说,过度使用代理模式会增加不必要的复杂性。 #### 三、单例模式(Singleton Pattern) 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。 **类图**: - `Singleton` 类通过私有构造函数确保外部无法直接实例化该类,并通过静态方法 `getInstance()` 返回唯一的实例。 **应用场景**: - 需要频繁地创建和销毁的对象。 - 资源管理器。 **优点**: - 控制资源的唯一实例,提高性能。 - 减少内存开销。 **缺点**: - 单例类的扩展性受限。 - 单例模式与单例类的职责没有完全分离。 #### 四、多例模式(Multiton Pattern) 多例模式是单例模式的一种变种,保证一个类有多个实例,并且这些实例可以根据特定的情况进行区分。 **类图**: - `Multiton` 类通常通过一个静态哈希表存储所有的实例,每个键对应一个实例。 **应用场景**: - 当系统中需要根据不同的标识符来区分多个实例时。 **优点**: - 比单例模式更灵活。 - 提高了程序的扩展性。 **缺点**: - 相比单例模式,实现更为复杂。 #### 五、工厂方法模式(Factory Method Pattern) 定义一个创建产品对象的工厂接口,但让实现决定实例化哪一个类。工厂方法让类的实例化推迟到子类。 **类图**: - `Creator` 接口定义了创建产品的方法。 - `ConcreteCreator` 类实现了 `Creator` 接口,并负责创建具体的 `Product` 类实例。 **应用场景**: - 当一个类不知道它所必须创建的对象的类的时候。 - 当一个类希望由其子类来指定它所创建的对象的时候。 **优点**: - 封装产品的创建过程。 - 简化客户端代码。 **缺点**: - 当产品的种类增加时,需要增加新的子类。 #### 六、抽象工厂模式(Abstract Factory Pattern) 提供一个接口,用于创建相关或依赖对象的族,而无需指定它们具体的类。 **类图**: - `AbstractFactory` 定义了一组用于创建不同类的接口。 - `ConcreteFactory` 实现了 `AbstractFactory`,并负责创建一组相关的 `ProductA` 和 `ProductB` 实例。 **应用场景**: - 当一个系统应该独立于它的产品创建、组合和表示时。 - 当一个系统被设计为支持所有同类对象的产品族时。 **优点**: - 更好的支持产品系列。 - 提高了程序的可扩展性。 **缺点**: - 当产品族中的产品数量增加时,系统将变得更加复杂。 #### 七、门面模式(Facade Pattern) 为子系统中的一组接口提供一个一致的界面,门面模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。 **类图**: - `SubsystemClass1`、`SubsystemClass2` 和 `SubsystemClass3` 是子系统的组成部分。 - `Facade` 类为子系统提供了一个简单的接口。 **应用场景**: - 当一个复杂的子系统需要一个简单的接口时。 - 当需要构建一个层次化的系统时。 **优点**: - 简化客户端代码。 - 降低系统的耦合度。 **缺点**: - 不适合非常简单的系统。 #### 八、适配器模式(Adapter Pattern) 将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。 **类图**: - `Target` 接口定义了客户期望的接口。 - `Adaptee` 类定义了需要适配的现有接口。 - `Adapter` 类实现了 `Target` 接口,并包含了 `Adaptee` 的一个实例。 **应用场景**: - 当希望复用一些现存的类,但是其接口不符合需求。 - 当不希望修改现存的类。 **优点**: - 可以复用现有的类。 - 系统的灵活性更好。 **缺点**: - 适配器模式只是适配了一个类,如果适配的类很多,那么适配器类也会相应增加。 #### 九、模板方法模式(Template Method Pattern) 定义一个操作中的算法骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 **类图**: - `AbstractClass` 定义了一个模板方法,其中包含了一些基本操作和一些抽象操作。 - `ConcreteClass1` 和 `ConcreteClass2` 继承自 `AbstractClass`,并实现了抽象操作。 **应用场景**: - 当子类之间共享算法时。 - 当需要保证一系列相关方法的调用顺序时。 **优点**: - 将算法步骤的实现细节封装起来。 - 提高了可扩展性。 **缺点**: - 如果一个父类中包含了大量的抽象方法,则子类的实现会很复杂。 #### 十、建造者模式(Builder Pattern) 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 **类图**: - `Director` 类负责调用 `Builder` 中的方法来构建复杂对象。 - `Builder` 接口定义了构建产品各个部分的方法。 - `ConcreteBuilder` 实现了 `Builder` 接口,并负责创建复杂对象的不同部分。 **应用场景**: - 当创建复杂对象的算法应该独立于部件构成和它们的装配方式时。 - 当构建过程必须允许被构造的对象有不同的表示时。 **优点**: - 封装变化。 - 分离构建和表示。 **缺点**: - 产品的组成部分需要一步一步构建,整体效率较低。 #### 十一、桥梁模式(Bridge Pattern) 将抽象部分与它的实现部分分离,使它们都可以独立地变化。 **类图**: - `Implementor` 接口定义了实现部分的接口。 - `RefinedAbstraction` 类扩展了 `Abstraction`,并可以通过 `Implementor` 接口引用实现部分。 - `ConcreteImplementor` 类实现了 `Implementor` 接口。 **应用场景**: - 当一个类的实现实现应该独立于类的行为时。 - 当一个抽象和它的实现都应该可以通过继承加以扩充时。 **优点**: - 分离抽象接口及其实现部分。 - 可以动态改变对象的实现部分。 **缺点**: - 需要正确识别出系统中两个独立变化的部分。 #### 十二、命令模式(Command Pattern) 将一个请求封装为一个对象,从而使用户可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。 **类图**: - `Command` 接口定义了一个执行操作的方法。 - `ConcreteCommand` 类实现了 `Command` 接口,并持有接收者的引用。 - `Invoker` 类调用 `Command` 的方法。 **应用场景**: - 当需要将请求调用者和请求接收者解耦。 - 当需要支持撤销操作时。 **优点**: - 降低了对象之间的耦合度。 - 新的命令可以很容易添加到系统中去。 **缺点**: - 使用命令模式可能会导致某些系统有过多的具体命令类。 #### 十三、装饰模式(Decorator Pattern) 动态地给一个对象添加一些额外的职责。就增加功能而言,装饰模式相比生成子类更加灵活。 **类图**: - `Component` 接口定义了对象的基本功能。 - `ConcreteComponent` 类实现了 `Component` 接口。 - `Decorator` 类也是 `Component` 的子类,并持有 `Component` 的引用。 **应用场景**: - 当需要扩展一个类的功能或者给一个类添加附加职责。 - 当需要动态地给一个对象添加或卸载功能。 **优点**: - 符合开闭原则。 - 具体构件类与装饰类可以独立变化。 **缺点**: - 会产生很多小对象。 - 装饰模式与继承关系的目的类似,但是比继承更加灵活。 #### 十四、迭代器模式(Iterator Pattern) 提供一种方法顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。 **类图**: - `Aggregate` 接口定义了创建并返回迭代器的方法。 - `ConcreteAggregate` 类实现了 `Aggregate` 接口,并负责创建具体的迭代器实例。 - `Iterator` 接口定义了访问和遍历元素的方法。 - `ConcreteIterator` 类实现了 `Iterator` 接口。 **应用场景**: - 当需要对容器对象的内容进行遍历时。 - 当需要为容器提供多种遍历方式时。 **优点**: - 简化了聚合类。 - 支持以不同的方式遍历同一个聚合对象。 **缺点**: - 增加了类的个数。 - 如果一个聚合对象有很多遍历方式,迭代器模式会变得复杂。 #### 十五、组合模式(Composite Pattern) 将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 **类图**: - `Component` 接口定义了所有节点的行为。 - `Leaf` 类实现了 `Component` 接口,并负责叶子节点的行为。 - `Composite` 类实现了 `Component` 接口,并负责组合节点的行为。 **应用场景**: - 当想表示对象的部分-整体层次结构时。 - 当用户需要处理树形结构时。 **优点**: - 简化客户端代码。 - 提高程序的灵活性。 **缺点**: - 设计比较复杂。 - 在使用组合模式时,需要定义那些非叶子节点都不使用的那些操作,这会使得这些操作对于非叶子节点来说是空操作。 #### 十六、观察者模式(Observer Pattern) 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 **类图**: - `Subject` 接口定义了注册观察者、移除观察者和通知观察者的方法。 - `ConcreteSubject` 类实现了 `Subject` 接口。 - `Observer` 接口定义了更新的方法。 - `ConcreteObserver` 类实现了 `Observer` 接口。 **应用场景**: - 当一个抽象模型有两个方面,其中一个方面依赖于另一方面时。 - 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变时。 **优点**: - 观察者和被观察者是抽象耦合的。 - 建立一套触发机制。 **缺点**: - 如果一个观察目标对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 - 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 #### 十七、责任链模式(Chain of Responsibility Pattern) 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 **类图**: - `Handler` 接口定义了一个处理请求的方法和一个设置后继者的方法。 - `ConcreteHandler` 类实现了 `Handler` 接口,并处理请求。 **应用场景**: - 有多个对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。 - 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。 **优点**: - 降低耦合度。 - 简化了对象。 **缺点**: - 不能保证请求一定被接收。 - 系统性能将受到一定影响。 #### 十八、访问者模式(Visitor Pattern) 表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 **类图**: - `Element` 接口定义了一个接受操作的方法。 - `ConcreteElement` 类实现了 `Element` 接口。 - `Visitor` 接口定义了一个访问方法。 - `ConcreteVisitor` 类实现了 `Visitor` 接口。 **应用场景**: - 对象结构中对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。 - 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作“污染”这些对象的类。 **优点**: - 符合单一职责原则。 - 优秀的扩展性。 **缺点**: - 增加了很多的类。 - 访问者模式破坏了封装性。 #### 十九、状态模式(State Pattern) 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。 **类图**: - `State` 接口定义了一个处理事件的方法。 - `ConcreteState` 类实现了 `State` 接口。 - `Context` 类包含了一个 `State` 对象的引用。 **应用场景**: - 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。 - 一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态。 **优点**: - 封装了转换规则。 - 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态。 **缺点**: - 状态模式的使用必然会随着增加状态对象的个数而增加类的个数。 - 状态模式的结构与实现都较为复杂。 #### 二十、原型模式(Prototype Pattern) 用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。 **类图**: - `Prototype` 接口定义了一个克隆自身的方法。 - `ConcretePrototype` 类实现了 `Prototype` 接口。 **应用场景**: - 当要实例化的类是在运行时刻指定时,例如,通过动态装载。 - 当要创建的对象具有复杂的内部结构。 **优点**: - 可以很方便地创建与原有对象类似的新对象。 - 可以避免构造过程中的重复性工作。 **缺点**: - 需要为每一个类配备一个克隆方法。 - 这些克隆方法需要协调一致,否则克隆出来的对象会出现问题。 #### 二十一、中介者模式(Mediator Pattern) 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。 **类图**: - `Mediator` 接口定义了与各个同事对象通信的方法。 - `ConcreteMediator` 类实现了 `Mediator` 接口。 - `Colleague` 接口定义了同事类的接口。 - `ConcreteColleague` 类实现了 `Colleague` 接口。 **应用场景**: - 当对象之间存在复杂的引用关系时。 - 当对象之间的作用需要简化并封装时。 **优点**: - 降低了对象间的耦合度。 - 可以使用中介者角色集中控制。 **缺点**: - 不适用于太多的对象的情况。 - 中介者对象会相当复杂。 #### 二十二、解释器模式(Interpreter Pattern) 给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。 **类图**: - `Expression` 接口定义了一个解释方法。 - `TerminalExpression` 类实现了 `Expression` 接口,并负责解析终结符表达式。 - `NonterminalExpression` 类实现了 `Expression` 接口,并负责解析非终结符表达式。 **应用场景**: - 可以将一个需要解释执行的语言中的句子表示为一个抽象语法树。 - 一些重复发生的解析问题。 **优点**: - 易于改变和扩展文法。 - 增加新的解释表达式的方式非常灵活。 **缺点**: - 解释器模式会引起类膨胀。 - 对于复杂文法难以维护。 #### 二十三、享元模式(Flyweight Pattern) 运用共享技术来有效地支持大量细粒度的对象。 **类图**: - `Flyweight` 接口定义了一个操作以共享的外部状态参数。 - `ConcreteFlyweight` 类实现了 `Flyweight` 接口。 - `UnsharedConcreteFlyweight` 类不被共享。 **应用场景**: - 当一个应用程序使用了大量的细粒度对象。 - 对象的大多数状态都可以外部化。 **优点**: - 大幅度减少内存中对象的数量。 - 减少内存空间的开销。 **缺点**: - 外部状态的维护会使逻辑复杂化。 - 如果读取外部状态需要较长时间,则会导致享元模式的效率下降。 #### 二十四、备忘录模式(Memento Pattern) 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。 **类图**: - `Memento` 接口定义了存储内部状态的方法。 - `Originator` 类负责创建和恢复备忘录。 - `CareTaker` 类负责保存和获取备忘录。 **应用场景**: - 需要保存/恢复数据的相关状态而又不想暴露其数据。 - 需要提供一个可回滚的操作。 **优点**: - 保持封装边界。 - 简化了 Originator。 **缺点**: - 消耗资源。 - 为了使备忘录能够独立于 Originator,备忘录可能需要存储 Originator 的一些内部状态,但这会增加备忘录的复杂性。 ### 设计原则 设计模式的应用往往伴随着设计原则的使用,以下是一些常用的设计原则: 1. **单一职责原则(Single Responsibility Principle)** - 一个类应该仅有一个引起它变化的原因。 - 优点:易于理解和维护。 - 缺点:可能增加类的数量。 2. **里氏替换原则(Liskov Substitution Principle)** - 子类必须能够替换它们的基类。 - 优点:提高程序的健壮性。 - 缺点:需要仔细设计接口。 3. **依赖倒置原则(Dependency Inversion Principle)** - 高层模块不应该依赖于低层模块,二者都应该依赖于抽象。 - 优点:减少类间的耦合。 - 缺点:增加系统的复杂度。 4. **接口隔离原则(Interface Segregation Principle)** - 使用多个专门的接口比使用单一的总接口要好。 - 优点:提高系统的灵活性。 - 缺点:可能增加接口的数量。 5. **迪米特法则(Law of Demeter)** - 一个对象应该对其他对象尽可能少的了解。 - 优点:降低系统的耦合度。 - 缺点:可能会增加系统的复杂度。 6. **开闭原则(Open/Closed Principle)** - 软件实体应当对扩展开放,对修改关闭。 - 优点:增加新功能而不影响旧功能。 - 缺点:需要精心设计类的接口。 ### 混编模式讲解 在实际开发中,经常会结合使用多种设计模式来解决问题。例如,在使用策略模式的同时,也可以结合工厂方法模式来创建策略对象,或者使用装饰模式来增强策略模式的功能。 ### 更新记录及相关说明 随着时间的推移,设计模式也在不断发展和完善。本书的后续版本中可能会增加新的设计模式或者对现有模式进行更深入的探讨。此外,书中还会提供一些关于设计模式应用的实际案例和最佳实践建议,帮助读者更好地理解和应用设计模式。 ### 后记 设计模式的学习是一个循序渐进的过程,初学者可以通过不断实践和学习来掌握这些模式。希望本书能够成为你探索设计模式世界的指南。
- my204448512013-12-24虽然很通俗,但是缺乏详细例子来说明
- 粉丝: 2
- 资源: 12
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助