百度网站推广方案,西城区网站建设推广seo,秦皇岛房产网,网站界面设计有哪些设计模式#xff08;Design Patterns#xff09;是软件工程中用于解决特定问题的一系列最佳实践。它们是经过时间考验的、被广泛认可的软件设计经验#xff0c;可以帮助开发者在面对常见问题时做出更好的设计决策。设计模式不是现成的代码#xff0c;而是一套指导原则…设计模式Design Patterns是软件工程中用于解决特定问题的一系列最佳实践。它们是经过时间考验的、被广泛认可的软件设计经验可以帮助开发者在面对常见问题时做出更好的设计决策。设计模式不是现成的代码而是一套指导原则用来指导开发者如何组织代码结构以便于更好地应对变化和提高代码的可维护性。
设计模式通常具有以下特点 普遍性设计模式解决的问题在软件设计中非常普遍很多设计问题都可以用相应的设计模式来解决。 可重用性设计模式提供了一种可重用的解决方案可以帮助开发者避免重复发明轮子。 灵活性设计模式通常具有良好的灵活性可以适应不同的应用场景。 可维护性使用设计模式可以提高代码的可维护性因为它们提供了一种标准化的解决方案。 可扩展性设计模式通常具有良好的可扩展性可以方便地添加新的功能。
1.设计模式分类 创建型模式Creational Patterns主要关注对象的创建隐藏对象创建的复杂性提高程序的可扩展性。常见的创建型模式有单例模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式。 结构型模式Structural Patterns主要关注对象的组合通过对象的组合提高程序的模块化。常见的结构型模式有适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式和代理模式。 行为型模式Behavioral Patterns主要关注对象之间的交互描述对象如何协作以完成某种任务。常见的行为型模式有责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式和访问者模式。
设计模式是软件工程中非常重要的概念掌握设计模式对于提高编程能力和设计能力非常有帮助。但是设计模式并不是万能的需要根据具体的应用场景来选择是否使用设计模式以及使用哪种设计模式。盲目地使用设计模式可能会导致过度设计反而降低程序的性能和可维护性。
2.使用场景
当然以下是以表格形式展示的设计模式及其使用场景的简要说明
设计模式目的使用场景示例单例模式保证一个类仅有一个实例并提供一个访问它的全局访问点- 日志记录器- 配置管理器工厂方法模式定义一个创建对象的接口让子类决定实例化哪个类- 各种工厂类如视频游戏工厂模式创建不同类型的角色抽象工厂模式解决一个系列的工厂用于创建一组相关或依赖的对象- GUI组件库- 汽车组装线建造者模式分离对象的构建过程和表示允许通过指定复杂对象类型和内容逐步构造一个复杂对象- 构建复杂对象如SQL语句构建器原型模式通过复制现有的实例来创建新的实例- 需要频繁创建开销较大的对象时适配器模式允许将不兼容的接口转换为一个可以使用的兼容接口- 兼容旧的类库- 第三方库的集成桥接模式分离抽象部分和实现部分使它们可以独立地变化- 当一个类存在多个变化维度时组合模式允许将对象组合成树形结构以表示“部分-整体”的层次结构- 处理类似文件系统的层次结构装饰器模式动态地添加额外的功能到一个对象上而不是通过继承- 扩展对象功能而不改变其类外观模式为子系统中的一组接口提供一个统一的接口- 简化复杂的系统接口享元模式运用共享技术有效地支持大量细粒度的对象- 当系统中存在大量相似对象时代理模式为其他对象提供一个代理或占位符以控制对这个对象的访问- 访问控制- 延迟初始化责任链模式使多个对象都有机会处理请求避免请求的发送者和接收者之间的耦合- 审批流程- 错误处理命令模式将一个请求封装为一个对象从而允许用户使用不同的请求来参数化其他对象- 宏系统- 事务系统解释器模式定义一个语言的文法并且建立一个解释器来解释该语言中的句子- 解析表达式或指令迭代器模式提供一种顺序访问一个聚合对象元素的方法而不暴露其内部的表示- 需要遍历聚合对象而不关心其内部结构中介者模式用一个中介对象来封装一系列对象之间的交互- 集中管理对象间的通信备忘录模式在不破坏封装性的前提下捕获一个对象的内部状态并在该对象之外保存这个状态- 提供对象状态的快照用于撤销操作观察者模式当对象间存在一对多关系时则使用观察者模式- 事件多级触发- 发布/订阅系统状态模式允许对象在其内部状态改变时改变它的行为- 行为随状态改变而改变的对象策略模式定义一系列算法把它们一个个封装起来并使它们可以互换- 需要动态地在运行时选择算法访问者模式表示一个作用于某对象结构中的各元素的操作它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作- 数据结构相对稳定但经常需要在此结构上定义新的操作
3. Demo
3.1. 创建型模式
3.1.1 单例模式
定义 单例模式确保一个类只有一个实例并提供一个全局访问点。
优点
全局访问提供了一个全局访问点便于控制实例数量。资源节约避免了创建多个对象时的资源浪费。线程安全在多线程环境中可以保证只创建一个实例。控制实例化可以控制对象的创建过程。
缺点
代码耦合单例模式可能会隐藏一些依赖关系导致代码耦合。可测试性差由于单例模式是全局的这使得单元测试变得困难。内存浪费单例对象在程序的整个生命周期内都占用内存。滥用单例模式有时会被滥用导致程序设计不灵活。
适用场景
需要确保在整个应用程序中只存在一个实例的情况如配置管理器、线程池、缓存等。
Demo
public class Singleton {// 私有构造函数防止外部实例化private Singleton() {}// 私有静态变量唯一的实例private static Singleton instance;// 公有静态方法提供全局访问点public static Singleton getInstance() {// 双重检查锁定确保线程安全if (instance null) {synchronized (Singleton.class) {if (instance null) {instance new Singleton();}}}return instance;}// 其他业务方法public void doSomething() {// ...}
}使用示例
public class Demo {public static void main(String[] args) {// 获取单例对象Singleton singleton Singleton.getInstance();// 使用单例对象singleton.doSomething();}
}请注意单例模式的实现方式有多种上面的实现是懒汉式单例模式它在第一次调用getInstance()方法时才创建实例并且使用了双重检查锁定来保证线程安全。根据具体需求单例模式的实现可能会有所不同。
3.1.2 工厂方法模式
工厂方法模式Factory Method Pattern是一种创建型设计模式用于处理对象的创建。在工厂方法模式中一个类将创建对象的任务委托给子类而不是自己创建对象。这样你可以在不修改工厂类的情况下通过继承和覆写子类的工厂方法来创建不同的对象。
定义 定义一个创建对象的接口但让子类决定要实例化的类是哪一个。工厂方法让类的实例化推迟到子类中进行。
优点
代码解耦将对象的创建与使用分离使得代码更加灵活易于扩展。提高可维护性当需要添加新的产品时只需要添加一个具体的产品类和相应的具体工厂类即可无需修改已有的工厂类。封装性隐藏了对象创建的细节调用者只需要知道类型不需要知道具体的实现。
缺点
每增加一个产品类别都需要增加一个产品类和一个工厂类这可能导致类的数量成倍增加。系统的抽象程度变得更高对于简单的情况可能会增加系统的复杂性。
适用场景
当需要创建的对象类型较多且具有共同的接口时。当需要将对象的创建与使用分离以提高扩展性和可维护性时。
Demo
// 产品接口
interface Product {void use();
}// 具体产品类
class ConcreteProductA implements Product {public void use() {System.out.println(Product A is being used.);}
}class ConcreteProductB implements Product {public void use() {System.out.println(Product B is being used.);}
}// 工厂接口
interface Factory {Product createProduct();
}// 具体工厂类
class ConcreteFactoryA implements Factory {public Product createProduct() {return new ConcreteProductA();}
}class ConcreteFactoryB implements Factory {public Product createProduct() {return new ConcreteProductB();}
}// 客户端代码
public class Client {public static void main(String[] args) {// 根据需求选择相应的工厂Factory factory new ConcreteFactoryA();Product product factory.createProduct();product.use();}
}在这个示例中Product 是产品接口ConcreteProductA 和 ConcreteProductB 是具体产品类。Factory 是工厂接口ConcreteFactoryA 和 ConcreteFactoryB 是具体工厂类它们分别创建相应的产品。客户端代码通过工厂接口与具体工厂类交互从而创建和使用产品。
工厂方法模式允许你通过继承和覆写工厂方法来灵活地创建不同类型的产品而不需要修改客户端代码这提高了系统的可扩展性。
3.1.3. 抽象工厂模式
抽象工厂模式Abstract Factory Pattern是一种创建型设计模式它提供了一个创建一系列相关或依赖对象的接口而不需要指定它们的具体类。这种模式通常用于当需要生成多个系列的产品时并且希望客户端不需要知道具体产品类的细节。
定义 提供一个接口用于创建一系列相关或依赖的对象而不指定它们的具体类。
优点
封装性具体产品类的实现细节被抽象工厂类所封装。扩展性增加新的产品族很方便不需修改现有系统。解耦产品等级结构的决策被推迟到对象创建时由具体工厂类实现。
缺点
难以支持新种类的产品如果需要在系统中引入新的工厂则需要修改抽象工厂接口。增加系统复杂性在添加新的产品对象时需要为每种产品提供一个相应的具体工厂类。
适用场景
当系统需要提供多个系列的产品并且这些产品之间存在相关性时。当系统需要独立地进行产品的系列扩展时。
Demo
// 产品接口
interface Product { void use();
}// 产品实现类A
class ProductA1 implements Product {public void use() {System.out.println(Product A1 is used);}
}// 产品实现类B
class ProductB1 implements Product {public void use() {System.out.println(Product B1 is used);}
}// 抽象工厂接口
interface AbstractFactory {Product createProduct();
}// 具体工厂实现类1
class ConcreteFactory1 implements AbstractFactory {public Product createProduct() {return new ProductA1();}
}// 产品实现类A
class ProductA2 implements Product {public void use() {System.out.println(Product A2 is used);}
}// 产品实现类B
class ProductB2 implements Product {public void use() {System.out.println(Product B2 is used);}
}// 具体工厂实现类2
class ConcreteFactory2 implements AbstractFactory {public Product createProduct() {return new ProductB2();}
}// 客户端代码
public class Client {public static void main(String[] args) {// 客户端代码针对抽象工厂编程AbstractFactory factory new ConcreteFactory1();Product product factory.createProduct();product.use();}
}在这个示例中Product 是一个产品接口ProductA1 和 ProductB1 是具体的产品实现。AbstractFactory 是一个抽象工厂接口定义了一个创建产品的方法。ConcreteFactory1 和 ConcreteFactory2 是具体工厂实现类它们分别创建属于各自系列的产品。客户端代码通过抽象工厂接口与具体工厂类交互从而创建和使用产品。
抽象工厂模式允许在不同的系列之间进行切换而不需要修改客户端代码这提高了系统的灵活性和可扩展性。
3.1.4. 建造者模式
建造者模式Builder Pattern是一种创建型设计模式用于将复杂对象的构建与其表示分离以便相同构建过程可以创建不同的表示。建造者模式通常适用于创建一个由多个部件或部分组成的复杂对象时允许用户只通过指定复杂对象的类型和内容就能构建和得到一个完整对象而不必知道其内部构建细节。
定义 将一个复杂对象的构建与其表示分离允许通过相同的构建过程创建不同的表示。
优点
解耦将对象的创建和表示分离使得修改和扩展建造者不影响对象的构建。封装性隐藏了对象构建的细节只暴露一个创建接口。灵活性用户不需要知道构建过程的具体细节只需要知道如何使用建造者接口即可构建出目标对象。
缺点
可能会创建过多的建造者类如果对象的内部变化较为复杂可能会需要多个建造者类这会增加系统的复杂性。对于只需要简单创建的对象使用建造者模式可能会过度设计。
适用场景
当需要生成一个由多个部件或部分组成的复杂对象时。当对象的构建过程独立于对象本身的其他业务逻辑时。
Demo
// 产品接口
interface Product {void assemblePart(String part);
}// 具体产品类
class ConcreteProduct implements Product {public void assemblePart(String part) {System.out.println(Product part part has been assembled.);}
}// 建造者接口
interface Builder {void buildPart1();void buildPart2();Product retrieveResult();
}// 具体建造者类
class ConcreteBuilder implements Builder {private Product product new ConcreteProduct();public void buildPart1() {product.assemblePart(Part1);}public void buildPart2() {product.assemblePart(Part2);}public Product retrieveResult() {return product;}
}// 指挥者
class Director {public void construct(Builder builder) {builder.buildPart1();builder.buildPart2();}
}// 客户端代码
public class Client {public static void main(String[] args) {// 创建指挥者和建造者Director director new Director();Builder builder new ConcreteBuilder();// 指挥者使用建造者来构建产品director.construct(builder);// 获得构建好的产品对象Product product builder.retrieveResult();product.assemblePart(Final Assembly);}
}在这个示例中Product 是产品接口ConcreteProduct 是具体产品实现。Builder 是建造者接口定义了构建复杂对象的各个部件的方法以及一个返回产品的接口。ConcreteBuilder 是具体建造者实现类它实现了建造者接口并创建了产品的具体实例。Director 是指挥者类它负责使用建造者来构建产品。客户端代码通过指挥者与建造者交互从而创建和使用产品。
建造者模式非常适合于创建包含多个部件或步骤的复杂对象并且这些部件或步骤的创建逻辑可能会变化的情况。
3.1.5 原型模式
原型模式Prototype Pattern是一种创建型设计模式它允许通过复制现有对象来创建新对象而不是通过创建新实例的方式。这种方式可以减少创建对象的开销特别是在创建对象成本较高时如初始化数据较为复杂或资源消耗较大。
定义 使用原型实例指定创建对象的种类并通过复制这个原型来创建新对象。
优点
简化对象创建通过复制已有对象来创建新对象避免了复杂的创建过程。性能优化对于创建成本较高的对象通过复制可以节省资源和时间。扩展性可以实现深拷贝和浅拷贝提供灵活的拷贝方式。
缺点
复制引用类型如果对象包含引用类型不当的复制可能会导致原始对象和复制对象共享同一引用类型这可能引起副作用。细小对象对于创建代价不大的对象使用原型模式可能会增加系统的复杂性。
适用场景
当创建新对象的成本较高时如需要创建大量相似对象时。当系统需要避免使用类时如动态加载对象。
最佳实践Demo含注释
// 原型接口
interface Prototype {Prototype clone(); // 克隆自身
}// 具体原型类
class ConcretePrototype implements Prototype {private String data;public ConcretePrototype(String data) {this.data data;}// 深拷贝克隆自身public Prototype clone() {try {return (ConcretePrototype) super.clone();} catch (CloneNotSupportedException e) {// 实际上由于实现了Cloneable接口这个异常不会发生return null;}}// getters and setterspublic String getData() {return data;}public void setData(String data) {this.data data;}
}// 客户端代码
public class Client {public static void main(String[] args) {// 创建原型对象ConcretePrototype prototype new ConcretePrototype(Original);// 克隆原型对象Prototype clone prototype.clone();// 使用克隆对象System.out.println(clone.getData()); // 输出: Original}
}在这个示例中Prototype 是原型接口定义了一个克隆自身的方法。ConcretePrototype 是具体原型类实现了原型接口的clone()方法用于克隆自己。客户端代码通过原型对象创建克隆对象从而避免了直接创建对象的开销。
原型模式非常适合于需要快速复制对象的场景尤其是在对象创建成本较高时。然而原型模式需要考虑对象的拷贝方式如深拷贝和浅拷贝以避免共享引用类型带来的问题。
3.2. 结构型模式
3.2.1. 适配器模式
适配器模式Adapter Pattern是一种结构型设计模式用于将不兼容的接口转换为一个可以使用的兼容接口。它允许原本由于接口不兼容而不能一起工作的类可以一起工作增加了类的可重用性。
定义 允许将不兼容的接口转换为一个可以使用的兼容接口。
优点
兼容性使得不兼容的接口可以协同工作。解耦将客户端与需要适配的类解耦客户端不需要知道适配的具体细节。灵活性可以设计一个类来适配多种不同的接口。
缺点
增加系统的复杂性过多使用适配器可能会使系统变得复杂。性能损失可能存在轻微的性能损失因为多了一层间接调用。
适用场景
当你希望复用一些类但这些类的接口与你的系统不兼容时。当你想创建一个可以与多种类协同工作的类并且这些类都具有不同的接口时。
Demo
// 目标接口定义客户端使用的特定领域相关的接口
interface Target {void request();
}// 适配者接口定义了被适配者的一个或多个不兼容的接口
interface Adaptee {void specificRequest();
}// 被适配者实现了一个特定的业务逻辑
class ConcreteAdaptee implements Adaptee {public void specificRequest() {System.out.println(Executing specificRequest in Adaptee);}
}// 适配器类将源接口转换成目标接口
class Adapter implements Target {private Adaptee adaptee;public Adapter(Adaptee adaptee) {this.adaptee adaptee;}public void request() {// 调用被适配者的方法adaptee.specificRequest();}
}// 客户端代码
public class Client {public static void main(String[] args) {// 创建被适配者Adaptee adaptee new ConcreteAdaptee();// 创建适配器将被适配者和目标接口关联起来Target target new Adapter(adaptee);// 使用适配器target.request();}
}在这个示例中Target 是目标接口定义了客户端使用的接口。Adaptee 是被适配者接口定义了被适配者的一个或多个不兼容的接口。ConcreteAdaptee 是被适配者的具体实现。Adapter 是适配器类实现了目标接口并通过组合被适配者对象来重用现有的接口。
适配器模式使得原本不兼容的类可以协同工作提高了类的可重用性。它允许客户端通过一个统一的接口来与其它类交互而不需要了解这些类的具体实现细节。
3.2.2. 桥接模式
桥接模式Bridge Pattern是一种结构型设计模式用于将抽象部分与其实现部分分离使它们可以独立地变化。桥接模式主要目的是将接口部分和实现部分分离开来从而能够独立地对它们进行扩展避免在任何一部分改变时都要重新生成整体的类层次结构。
定义 将抽象部分与其实现部分分离使它们可以独立地变化。
优点
解耦桥接模式使抽象和实现分离从而降低了它们之间的耦合。扩展性可以独立地扩展抽象和实现而不需要改动另一部分。复用性实现部分可以在不同的抽象接口中被复用。
缺点
复杂性桥接模式可能会增加系统的理解与设计的复杂性。开销对于性能要求严格的场合由于桥接模式引入了间接层可能造成性能的损耗。
适用场景
当一个类存在两个独立变化的维度时例如一个维度是逻辑行为另一个维度是显示行为。当希望复用现有的类层次时并且希望将多个抽象类和多个具体类组合成多个不同的行为。
Demo
// 抽象部分
abstract class Abstraction {protected Implementor implementor;public Abstraction(Implementor implementor) {this.implementor implementor;}public void operation() {implementor.operationImpl();}
}// 实现部分的接口
interface Implementor {void operationImpl();
}// 实现部分的具体实现
class ConcreteImplementorA implements Implementor {public void operationImpl() {System.out.println(ConcreteImplementorA operation);}
}class ConcreteImplementorB implements Implementor {public void operationImpl() {System.out.println(ConcreteImplementorB operation);}
}// 客户端代码
public class Client {public static void main(String[] args) {// 创建实现部分Implementor implementor new ConcreteImplementorA();// 创建抽象部分绑定实现部分Abstraction abstraction new ConcreteAbstraction(implementor);abstraction.operation();}
}// 具体的抽象部分
class ConcreteAbstraction extends Abstraction {public ConcreteAbstraction(Implementor implementor) {super(implementor);}// 可以覆写operation()方法以扩展行为public void operation() {// 先调用Implementor的行为implementor.operationImpl();// 再执行Abstraction的额外行为additionalOperation();}private void additionalOperation() {System.out.println(Additional operation in ConcreteAbstraction);}
}在这个示例中Abstraction 是抽象部分它包含一个对Implementor的引用并定义了一个operation()方法。Implementor 是实现部分的接口定义了一个operationImpl()方法。ConcreteImplementorA 和 ConcreteImplementorB 是实现部分的具体实现。ConcreteAbstraction 是具体的抽象部分它继承自Abstraction并可以扩展行为。
桥接模式通过将抽象和实现分离使得两者可以独立地扩展和复用从而提高了系统的灵活性和可维护性。
3.2.3. 组合模式
组合模式Composite Pattern也被称为“部分-整体”模式是一种结构型设计模式。它允许用户以一致的方式处理个别对象和对象组合。组合模式通过提供一个统一的接口来隐藏对象和对象组合之间的差异使得客户端代码可以像处理对象一样处理对象的组合。
定义 将对象组合成树形结构以表示“部分-整体”的层次结构使得用户对单个对象和组合对象的使用具有一致性。
优点
透明性叶子节点和组合节点对客户端来说没有区别客户端可以统一地使用。灵活性可以很容易地增加新的叶子节点和组合节点。安全性组合结构的安全和稳固因为客户端代码不需要改变就可以支持新的组合。
缺点
增加设计复杂性在简单的情况下使用组合模式可能增加设计的理解难度。使用限制对树结构的节点增加、删除和搜索等操作可能需要额外的操作。
适用场景
当需要将对象组合成树形结构时。当希望用户对单个对象和组合对象的使用具有一致性时。
Demo
// 组件接口
interface Component {void operation();
}// 叶子节点
class Leaf implements Component {public void operation() {System.out.println(Leaf operation.);}
}// 组合节点
class Composite implements Component {private ListComponent children new ArrayList();public void add(Component component) {children.add(component);}public void remove(Component component) {children.remove(component);}public void operation() {for (Component child : children) {child.operation();}}
}// 客户端代码
public class Client {public static void main(String[] args) {// 创建组合节点和叶子节点Composite composite new Composite();Component leaf1 new Leaf();Component leaf2 new Leaf();// 将叶子节点添加到组合节点composite.add(leaf1);composite.add(leaf2);// 通过组合节点统一操作叶子节点composite.operation();}
}在这个示例中Component 是组件接口定义了组合中所有对象的一致操作。Leaf 是叶子节点实现了组件接口的具体对象。Composite 是组合节点它实现了与叶子节点相同的接口并且在内部聚合了其他组件可以是叶子节点也可以是其他组合节点。
组合模式允许客户端通过统一的接口来处理对象和对象的组合隐藏了如何通过组合来构建整体的复杂性。这种模式适用于创建树状结构的应用程序例如文件系统、组织结构图等。
3.2.4. 装饰器模式
装饰器模式Decorator Pattern是一种结构型设计模式它允许向一个现有的对象添加新的功能同时又不改变其结构。这种类型的设计模式属于对象的组合它是作为现有类的一个包装。
定义 动态地添加额外的功能到一个对象上同时又不改变其类。
优点
灵活性通过使用装饰器可以在运行时给对象添加功能。扩展性可以为老系统添加装饰器以提高其性能。代码复用装饰器可以被多个类重用。
缺点
增加系统的复杂性过度使用装饰器模式可能会使系统变得复杂。可能会引起性能问题在对象周围过度包装装饰器可能会影响性能。
适用场景
当需要为对象添加功能时。当不希望使用继承或使用继承不方便时。
Demo
// 抽象组件
interface Component {void operate();
}// 具体组件
class ConcreteComponent implements Component {public void operate() {System.out.println(ConcreteComponent operate);}
}// 抽象装饰器
interface Decorator extends Component {// 可以设置一个关联组件的引用void setComponent(Component component);
}// 具体装饰器
class ConcreteDecoratorA implements Decorator {private Component component;public void setComponent(Component component) {this.component component;}public void operate() {if (component ! null) {component.operate();}// 添加额外的功能addedBehavior();}private void addedBehavior() {System.out.println(ConcreteDecoratorA added behavior);}
}// 客户端代码
public class Client {public static void main(String[] args) {Component component new ConcreteComponent();component new ConcreteDecoratorA();component.setComponent(component);component.operate();}
}在这个示例中Component 是一个抽象组件定义了对象的接口。ConcreteComponent 是一个具体组件实现了抽象组件定义的接口。Decorator 是一个抽象装饰器它也遵循与组件相同的接口并且持有一个组件的引用。ConcreteDecoratorA 是一个具体装饰器通过实现Decorator接口它向组件添加了额外的行为。
装饰器模式允许你通过组合对象来提供新的行为而不是通过继承。这使得你可以在不影响其他对象的情况下控制对象的装饰从而提供更灵活的设计。
3.2.5. 外观模式
外观模式Facade Pattern是一种结构型设计模式它提供了一个统一的接口来访问一个子系统中的一组接口。外观模式定义了一个高层接口让子系统中的复杂交互被简化成单一入口。这种设计模式隐藏了系统的复杂性并向客户端提供了一个客户端可以访问系统的接口。
定义 为子系统中的一组接口提供一个统一的接口让子系统更容易使用。
优点
简化接口客户端通过一个接口就能与子系统交互无需了解子系统内部的复杂性。解耦减少了客户端与子系统组件的依赖提高了子系统的独立性。层次结构客户端只需要关注外观对象不需要了解子系统内部的实现细节。
缺点
理解困难对于不熟悉系统的新开发者外观模式可能会隐藏内部功能导致理解上的困难。灵活性降低使用外观模式可能会限制子系统的部分功能因为外观对象可能只提供了有限的接口。
适用场景
当需要提供一个简单接口来访问复杂的子系统时。当需要客户端与多个子系统组件交互并且这些交互被集中在一个对象中时。
Demo
// 子系统接口
interface Subsystem {void operation();
}// 子系统实现
class SubsystemOne implements Subsystem {public void operation() {System.out.println(SubsystemOne operation);}
}class SubsystemTwo implements Subsystem {public void operation() {System.out.println(SubsystemTwo operation);}
}// 外观类
class Facade {private Subsystem subsystemOne;private Subsystem subsystemTwo;public Facade() {subsystemOne new SubsystemOne();subsystemTwo new SubsystemTwo();}public void operation() {// 协调子系统中的对象完成一系列操作subsystemOne.operation();subsystemTwo.operation();}
}// 客户端代码
public class Client {public static void main(String[] args) {Facade facade new Facade();facade.operation();}
}在这个示例中Subsystem 是子系统接口定义了子系统的操作。SubsystemOne 和 SubsystemTwo 是子系统的具体实现。Facade 是外观类它聚合了子系统中的对象提供了一个统一的操作接口。客户端通过外观对象的operation()方法与子系统交互而不需要知道子系统内部的实现细节。
外观模式通过提供一个简化的接口使得客户端可以更容易地与复杂的子系统交互同时隐藏了子系统的复杂性。这种模式非常适合于需要简化系统访问的场景。
3.2.6. 享元模式
享元模式Flyweight Pattern是一种结构型设计模式它主要用于减少创建对象的数量从而减少内存占用和提高性能。享元模式通过共享对象来实现这一目的确保大量相同或相似对象可以通过共享的方式重用。
定义 使用共享对象来支持大量的细粒度对象这些对象外部状态不同但是内部状态可以保持一致。
优点
减少内存占用通过共享对象减少了内存中对象的数量。提高性能减少了创建和销毁对象的开销。降低耦合度享元对象不依赖于其他对象的状态。
缺点
增加了系统的复杂性需要分离内部状态和外部状态这可能使得系统设计变得更复杂。状态共享可能导致的并发问题如果享元对象的内部状态被多个客户端共享需要特别注意线程安全。
适用场景
当一个应用程序使用了大量的对象而这些对象造成了很大的内存开销时。当对象的大多数状态可以外部化并且可以由对象之外的参数来维护时。
Demo
// 享元接口
interface Flyweight {void operation(String extrinsicState);
}// 具体享元类
class ConcreteFlyweight implements Flyweight {private String intrinsicState; // 内部状态public ConcreteFlyweight(String intrinsicState) {this.intrinsicState intrinsicState;}public void operation(String extrinsicState) {// 操作内部状态和外部状态System.out.println(Operation on internal state: intrinsicState , with extrinsic state: extrinsicState);}
}// 享元工厂用于创建并管理享元对象
class FlyweightFactory {private static MapString, Flyweight flyweights new HashMap();public static Flyweight getFlyweight(String intrinsicState) {if (!flyweights.containsKey(intrinsicState)) {flyweights.put(intrinsicState, new ConcreteFlyweight(intrinsicState));}return flyweights.get(intrinsicState);}
}// 客户端代码
public class Client {public static void main(String[] args) {// 使用享元工厂获取享元对象Flyweight flyweightOne FlyweightFactory.getFlyweight(State1);flyweightOne.operation(StateA);Flyweight flyweightTwo FlyweightFactory.getFlyweight(State2);flyweightTwo.operation(StateB);}
}在这个示例中Flyweight 是享元接口定义了享元对象的操作。ConcreteFlyweight 是具体享元类它包含了内部状态并且实现了Flyweight接口。FlyweightFactory 是享元工厂负责创建和管理享元对象确保相同内部状态的对象不会重复创建。
享元模式通过共享相同内部状态的享元对象来减少内存占用适用于创建大量相似对象的场景。然而这种模式需要仔细设计以确保对象的内部状态和外部状态被适当地分离和维护。
3.2.7. 代理模式
代理模式Proxy Pattern是一种结构型设计模式它为其他对象提供一个代理或占位符以控制对这个对象的访问。代理模式可以在不改变对象的代码的情况下为对象添加额外的功能例如延迟初始化、访问控制、日志记录、缓存等。
定义 为其他对象提供一个代理或占位符以控制对这个对象的访问。
优点
控制访问可以控制对原始对象的访问提供权限检查。延迟初始化可以在需要时才创建实际对象提高性能。其他功能可以添加额外的功能如日志记录、性能监控等。
缺点
增加复杂性可能会增加系统的复杂性。性能影响有时代理对象可能会引入一些性能开销。
适用场景
当需要对对象创建加以控制时。当需要为对象添加额外的功能如延迟初始化、访问控制等。
Demo
// 真实主题接口
interface Subject {void request();
}// 真实主题实现
class RealSubject implements Subject {public void request() {System.out.println(RealSubject: Handling request.);}
}// 代理主题实现了与真实主题相同的接口
class ProxySubject implements Subject {private RealSubject realSubject;public void request() {if (realSubject null) {// 延迟初始化realSubject new RealSubject();}realSubject.request();}
}// 客户端代码
public class Client {public static void main(String[] args) {// 使用代理对象Subject proxySubject new ProxySubject();proxySubject.request();}
}在这个示例中Subject 是真实主题接口定义了真实对象需要实现的方法。RealSubject 是真实主题实现实现了主题接口的具体业务逻辑。ProxySubject 是代理主题它实现了与真实主题相同的接口并在内部维护了对真实主题的引用。客户端通过代理对象来访问真实对象代理对象可以在内部控制对真实对象的访问。
代理模式可以在不修改真实对象的情况下控制对真实对象的访问并在访问过程中添加额外的功能。这种模式非常适合于需要对对象访问进行控制或添加额外功能的场景。
3.3. 行为型模式
3.3.1. 责任链模式
责任链模式Chain of Responsibility Pattern是一种行为型设计模式它允许将一个请求沿着处理者链进行传递直到有处理者处理它为止。每个处理者都有责任去处理请求或者将它转发给链中的下一个处理者。这种模式常用于在多个对象之间传递请求直到某个对象能够处理该请求。
定义 使多个对象都有机会处理请求从而避免请求的发送者和接收者之间的耦合关系。
优点
解耦将请求的发送者和接收者解耦。可扩展性可以动态地添加或删除处理者或者改变处理者的顺序。灵活性请求的处理流程更加灵活。
缺点
性能请求可能会经过多个处理者可能存在性能问题。不确定性不能保证请求一定被处理除非明确设计。循环依赖不当的设计可能会导致循环依赖的问题。
适用场景
当一个请求有多个对象可以处理且具体哪个对象处理该请求由运行时刻决定。当你想通过一个集中的入口点将职责委托给多个处理对象时。
Demo
// 请求接口
interface Request {String getRequestData();
}// 具体请求
class ConcreteRequest implements Request {private String data;public ConcreteRequest(String data) {this.data data;}public String getRequestData() {return data;}
}// 处理者接口
abstract class Handler {protected Handler nextHandler; // 下一个处理者public void setNext(Handler nextHandler) {this.nextHandler nextHandler;}abstract void handleRequest(Request request);
}// 具体处理者
class ConcreteHandler1 extends Handler {private static final String RESPONSIBILITY Request Type A;public void handleRequest(Request request) {if (RESPONSIBILITY.equals(request.getRequestData())) {System.out.println(Handler 1 is handling this request.);} else {if (nextHandler ! null) {nextHandler.handleRequest(request);}}}
}class ConcreteHandler2 extends Handler {private static final String RESPONSIBILITY Request Type B;public void handleRequest(Request request) {if (RESPONSIBILITY.equals(request.getRequestData())) {System.out.println(Handler 2 is handling this request.);} else {if (nextHandler ! null) {nextHandler.handleRequest(request);}}}
}// 客户端代码
public class Client {public static void main(String[] args) {Handler handler1 new ConcreteHandler1();Handler handler2 new ConcreteHandler2();// 构建责任链handler1.setNext(handler2);// 创建请求并发送Request request new ConcreteRequest(Request Type A);handler1.handleRequest(request);}
}在这个示例中Request 是请求接口定义了请求必须实现的方法。ConcreteRequest 是具体请求实现了请求接口。Handler 是处理者接口定义了处理请求的方法并且包含一个指向下一个处理者的引用。ConcreteHandler1 和 ConcreteHandler2 是具体处理者它们实现了处理请求的逻辑并根据请求的类型决定是否处理请求或将请求转发给链中的下一个处理者。
责任链模式通过对象组成的链结构来处理请求使得请求的发送者不必知道请求的处理者是谁从而降低了系统的耦合度。
3.3.2. 命令模式
命令模式Command Pattern是一种行为型设计模式它将一个请求封装为一个对象从而允许用户使用不同的请求、队列或日志请求来参数化其他对象。命令模式通常用于解耦请求的发送者和接收者让发送者和接收者之间通过命令对象进行交互。
定义 将一个请求封装为一个对象从而允许用户使用不同的请求来参数化其他对象。
优点
解耦命令模式将调用操作的对象与知道如何实现该操作的对象解耦。扩展性可以容易地扩展新的命令。宏命令可以组合多个命令到一个宏命令中。
缺点
增加系统复杂性可能会增加系统中对象的数量。命令过多如果系统中命令对象太多可能会导致管理上的复杂性。
适用场景
当需要将请求封装为对象从而可以用不同的请求对客户进行参数化时。当需要支持取消操作时。当需要支持事务和日志功能时。
Demo
// 命令接口
interface Command {void execute();
}// 接收者知道如何实施与执行一个请求相关的操作
class Receiver {public void action() {System.out.println(Receiver performs action);}
}// 具体的命令类实现execute()方法负责调用接收者的功能
class ConcreteCommand implements Command {private Receiver receiver;public ConcreteCommand(Receiver receiver) {this.receiver receiver;}public void execute() {receiver.action();}
}// 调用者要求命令对象执行请求
class Invoker {public void invoke(Command command) {command.execute();}
}// 客户端代码
public class Client {public static void main(String[] args) {// 创建接收者对象Receiver receiver new Receiver();// 创建具体命令对象将接收者对象传入Command command new ConcreteCommand(receiver);// 创建调用者对象Invoker invoker new Invoker();// 通过调用者对象执行命令对象invoker.invoke(command);}
}在这个示例中Command 是命令接口定义了执行命令的方法。Receiver 是接收者类它知道如何实施与执行一个请求相关的操作。ConcreteCommand 是具体命令类它实现了命令接口的execute()方法负责调用接收者的功能。Invoker 是调用者类它要求命令对象执行请求。
命令模式通过将请求封装为对象允许用户使用不同的请求来参数化其他对象从而实现请求发送者和接收者的解耦。这种模式非常适合于需要支持撤销操作、事务和日志功能的场景。
3.2.3. 解释器模式
解释器模式Interpreter Pattern是一种行为型设计模式用于定义一个语言的语法规则并且构建一个解释器来解释该语言中的句子。这种模式通常用于执行一种特定类型语言通常是非通用的、简单的或领域特定语言的解释。
定义 定义一个语言的语法规则并且建立一个解释器来解释该语言中的句子。
优点
扩展性可以方便地添加新的语言文法和表达式。可读性对于特定领域的问题使用解释器模式可以提高可读性。易于修改和扩展文法。
缺点
效率问题对于复杂的文法解释器模式可能导致性能瓶颈。错误诊断解释器模式通常难以诊断错误因为语句的解析过程通常很复杂。
适用场景
当有一个语言需要解释执行并且可以定义它的文法时。当需要提供一个简单的解释器时。
Demo
// 抽象表达式类
abstract class Expression {public abstract boolean interpret(String command);
}// 终端表达式
class TerminalExpression extends Expression {public boolean interpret(String command) {// 解释简单的命令System.out.println(Interpreting command as a terminal expression.);return true; // 假设命令被成功解释}
}// 非终端表达式
class NonTerminalExpression extends Expression {private Expression expression;public NonTerminalExpression(Expression expression) {this.expression expression;}public boolean interpret(String command) {// 解释复合命令System.out.println(Interpreting command as a non-terminal expression.);return expression.interpret(command); // 递归解释子表达式}
}// 解释器的上下文
class Context {// 存储解释器需要的上下文信息
}// 客户端代码
public class Client {public static void main(String[] args) {Expression terminal new TerminalExpression();Expression nonTerminal new NonTerminalExpression(terminal);// 创建上下文Context context new Context();// 解释命令boolean result nonTerminal.interpret(command);System.out.println(Command interpreted: result);}
}在这个示例中Expression 是抽象表达式类定义了解释方法。TerminalExpression 是终端表达式类它实现了简单的命令解释。NonTerminalExpression 是非终端表达式类它组合了一个表达式并且可以解释复合命令。Context 是解释器的上下文它存储解释过程中需要的信息。
解释器模式允许你定义一个简单的语言的文法并构建一个解释器来解释该语言的句子。这种模式非常适合于需要解释特定领域语言的场景。然而对于复杂或通用的语言使用解释器模式可能导致性能问题和难以维护的代码。
3.2.4. 迭代器模式
迭代器模式Iterator Pattern是一种行为型设计模式它允许用户按顺序访问一个聚合对象中的元素而不需要暴露其内部的表示。迭代器模式提供了一种通过统一的接口来遍历不同类型集合的方法。
定义 提供一种方法顺序访问聚合对象的元素同时保持对象的封装。
优点
解耦迭代器模式使得聚合对象的内部表示与客户端分离客户端不需要知道集合的具体实现。扩展性可以在不修改客户端代码的情况下向系统中添加新的聚合和迭代器。一致性提供了一种统一的方式来访问聚合对象。
缺点
对于简单的集合可能会增加编程复杂性。迭代器的维护成本需要为每个聚合类型都编写迭代器类。
适用场景
当需要访问一个聚合对象但不能改变其内部结构时。当需要为聚合对象提供多种方式来遍历时。
Demo
// 聚合接口
interface Aggregate {Iterator createIterator();
}// 具体聚合类
class ConcreteAggregate implements Aggregate {private List items new ArrayList();public void addItem(String item) {items.add(item);}public Iterator createIterator() {return new ConcreteIterator(this);}
}// 迭代器接口
interface Iterator {boolean hasNext();Object next();
}// 具体迭代器类
class ConcreteIterator implements Iterator {private ConcreteAggregate aggregate;private int currentIndex 0;public ConcreteIterator(ConcreteAggregate aggregate) {this.aggregate aggregate;}public boolean hasNext() {return currentIndex aggregate.items.size();}public Object next() {return aggregate.items.get(currentIndex);}
}// 客户端代码
public class Client {public static void main(String[] args) {ConcreteAggregate aggregate new ConcreteAggregate();aggregate.addItem(Item1);aggregate.addItem(Item2);aggregate.addItem(Item3);Iterator iterator aggregate.createIterator();while (iterator.hasNext()) {Object item iterator.next();System.out.println(item);}}
}在这个示例中Aggregate 是聚合接口定义了创建迭代器的方法。ConcreteAggregate 是具体聚合类它实现了聚合接口并负责维护一个元素列表。Iterator 是迭代器接口定义了迭代集合元素的方法。ConcreteIterator 是具体迭代器类它实现了迭代器接口并负责跟踪当前的遍历位置。
迭代器模式通过提供一个统一的接口来遍历聚合对象使得客户端可以一致地访问不同类型的集合而不需要关心集合的具体实现。这种模式非常适合于需要提供一致访问接口的场景。
3.2.5. 中介者模式
中介者模式Mediator Pattern是一种行为型设计模式它定义了一个中介对象用于封装一系列对象之间的交互。中介者使各对象不需要显示地相互引用从而使耦合度降低而且可以独立地改变它们之间的交互。
定义 用一个中介对象来封装一系列的对象交互使各对象之间不需要相互显示引用。
优点
降低耦合度减少了对象之间的依赖使得它们可以独立地变化。集中控制中介者可以控制对象之间的交互方式可以简化系统的理解。易于扩展增加新的同事对象即通过中介者进行通信的对象相对容易。
缺点
中介者过于复杂如果中介者承担了太多的职责它可能会变得非常复杂。性能问题在某些情况下使用中介者可能导致系统性能降低因为所有交互都通过中介者来转发。
适用场景
当一个系统由许多类似对象组成而这些对象之间的通信非常频繁时。当对象之间的交互非常复杂并且当你希望将这些交互封装起来时。
Demo
// 中介者接口
interface Mediator {void register(String colleagueName, Colleague colleague);void relay(String colleagueName);
}// 具体中介者
class ConcreteMediator implements Mediator {private MapString, Colleague colleagues new HashMap();public void register(String colleagueName, Colleague colleague) {colleagues.put(colleagueName, colleague);}public void relay(String colleagueName) {Colleague colleague colleagues.get(colleagueName);if (colleague ! null) {colleague.notify();}}
}// 同事类接口
interface Colleague {void setMediator(Mediator mediator);void notify();
}// 具体同事类
class ConcreteColleagueA implements Colleague {private ConcreteMediator mediator;public void setMediator(ConcreteMediator mediator) {this.mediator mediator;}public void notify() {System.out.println(Colleague A is notified.);}public void businessMethod() {// 业务逻辑mediator.relay(ColleagueB);}
}class ConcreteColleagueB implements Colleague {private ConcreteMediator mediator;public void setMediator(ConcreteMediator mediator) {this.mediator mediator;}public void notify() {System.out.println(Colleague B is notified.);}// ...
}// 客户端代码
public class Client {public static void main(String[] args) {// 创建中介者ConcreteMediator mediator new ConcreteMediator();// 创建同事对象并设置中介者ConcreteColleagueA colleagueA new ConcreteColleagueA();colleagueA.setMediator(mediator);ConcreteColleagueB colleagueB new ConcreteColleagueB();colleagueB.setMediator(mediator);// 中介者注册同事对象mediator.register(ColleagueA, colleagueA);mediator.register(ColleagueB, colleagueB);// 某个同事对象的业务逻辑触发交互colleagueA.businessMethod();}
}在这个示例中Mediator 是中介者接口定义了中介者的行为。ConcreteMediator 是具体中介者它管理同事对象之间的交互。Colleague 是同事类接口定义了同事对象与中介者之间的通信协议。ConcreteColleagueA 和 ConcreteColleagueB 是具体同事类它们实现了同事类接口并通过中介者与其他同事对象进行通信。
中介者模式通过一个中介者对象来封装多个对象之间的交互从而降低了对象之间的耦合度使得对象可以更加独立地变化。这种模式非常适合于系统中对象之间存在复杂交互的情况。
3.2.6. 备忘录模式
备忘录模式Memento Pattern是一种行为型设计模式用于在不破坏封装性的前提下捕获一个对象的内部状态并在该对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。备忘录模式常用于实现软件中的撤销功能或者在需要回滚操作时使用。
定义 在不破坏封装性的前提下捕获一个对象的内部状态并在该对象之外保存这个状态以后可以将对象恢复到原先保存的状态。
优点
安全性备忘录可以保护原始对象的内部状态不被外部直接修改。灵活性可以捕获和保存多个状态实现多状态的存储和恢复。
缺点
资源消耗如果保存的状态过多可能会消耗较多的内存。复杂性增加了系统的复杂性需要理解状态的保存和恢复机制。
适用场景
当需要保存一个对象的当前状态以便在将来恢复时使用。当对象的某些状态信息必须保密不能直接暴露给其他对象时。
Demo
// 发起人角色需要被保存和恢复状态
class Originator {private String state;public String getState() {return state;}public void setState(String state) {this.state state;}// 创建一个备忘录public Memento saveStateToMemento() {return new Memento(state);}// 从备忘录恢复状态public void getStateFromMemento(Memento memento) {state memento.getState();}
}// 备忘录角色存储发起人的内部状态
class Memento {private String state;public Memento(String state) {this.state state;}public String getState() {return state;}
}// 负责人角色负责创建和管理备忘录
class Caretaker {private Memento memento;public void setMemento(Memento memento) {this.memento memento;}public Memento getMemento() {return memento;}
}// 客户端代码
public class Client {public static void main(String[] args) {Originator originator new Originator();originator.setState(State #1);// 创建备忘录并保存状态Caretaker caretaker new Caretaker();caretaker.setMemento(originator.saveStateToMemento());// 修改发起人状态originator.setState(State #2);// 从备忘录恢复状态originator.getStateFromMemento(caretaker.getMemento());System.out.println(Restored state: originator.getState());}
}在这个示例中Originator 是发起人角色它拥有需要被保存和恢复的状态。saveStateToMemento() 方法用于创建备忘录并保存当前状态getStateFromMemento() 方法用于从备忘录恢复状态。
Memento 是备忘录角色它存储发起人的内部状态。为了保持封装性备忘录通常只提供给负责人访问。
Caretaker 是负责人角色它负责创建和管理备忘录。负责人不应该知道备忘录内部是如何实现的因此它只负责保存和提供备忘录。
备忘录模式通过引入备忘录和负责人角色允许在不破坏发起人封装性的前提下捕获和恢复发起人的状态。这种模式非常适合于需要实现撤销或回滚功能的场景。
3.2.7. 观察者模式
观察者模式Observer Pattern是一种行为型设计模式它定义了对象之间的一对多依赖关系当一个对象改变状态时它的所有依赖者都会收到通知并自动更新。观察者模式常用于实现事件处理系统如图形用户界面的事件处理。
定义 当对象间存在一对多关系时则使用观察者模式。一个被观察的对象变化时所有依赖它的对象都会得到通知并自动更新。
优点
解耦观察者模式可以实现主题对象与其他对象之间的松耦合。可扩展性可以在不修改主题对象的情况下添加新的观察者。中间人提供了一个主题对象和其他观察者对象之间的中介对象。
缺点
性能当一个主题对象有大量观察者或者观察者之间的依赖过于紧密时通知的开销可能会很大。循环依赖如果处理不当观察者模式可能会导致循环依赖。
适用场景
当一个对象观察目标的状态改变需要使其他对象观察者自动更新时。当需要建立一个事件多级触发机制时。
最佳实践Demo含注释
// 观察者接口
interface Observer {void update(String message);
}// 主题接口
interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}// 具体主题类
class ConcreteSubject implements Subject {private ListObserver observers new ArrayList();private String state;public void registerObserver(Observer o) {if (!observers.contains(o)) {observers.add(o);}}public void removeObserver(Observer o) {observers.remove(o);}public void notifyObservers() {for (Observer observer : observers) {observer.update(this.state);}}public void setState(String state) {this.state state;notifyObservers();}public String getState() {return state;}
}// 具体观察者类
class ConcreteObserver implements Observer {private ConcreteSubject subject;public ConcreteObserver(ConcreteSubject subject) {this.subject subject;}public void printState() {System.out.println(Observer state: subject.getState());}public void update(String message) {printState();}
}// 客户端代码
public class Client {public static void main(String[] args) {ConcreteSubject subject new ConcreteSubject();// 创建观察者并注册到主题Observer observer1 new ConcreteObserver(subject);subject.registerObserver(observer1);Observer observer2 new ConcreteObserver(subject);subject.registerObserver(observer2);// 改变主题状态观察者收到通知并更新subject.setState(New State);}
}在这个示例中Observer 是观察者接口定义了更新接口。Subject 是主题接口定义了注册、移除和通知观察者的方法。ConcreteSubject 是具体主题类它实现了主题接口并维护了观察者列表。当主题对象的状态发生变化时它会通知所有注册的观察者。
ConcreteObserver 是具体观察者类它实现了观察者接口并定义了接收到通知后的更新行为。
客户端代码创建了主题对象和观察者对象并将观察者注册到主题对象上。当主题对象的状态发生变化时所有注册的观察者都会收到通知并自动更新。
观察者模式通过定义对象之间的依赖关系允许在主题对象状态变化时自动更新观察者对象从而实现解耦和自动更新。这种模式非常适合于需要实现事件处理和响应的场景。
3.2.8. 状态模式
状态模式State Pattern是一种行为型设计模式它允许一个对象在其内部状态改变时改变它的行为。这个对象看起来似乎修改了它的类。状态模式通过将各种状态转移逻辑分布到表示各种状态的一系列类中将对象的状态逻辑与对象本身分离实现了对象行为的动态变化。
定义 允许对象在内部状态改变时改变它的行为这个对象看起来就像改变了它的类一样。
优点
封装性将与特定状态相关的行为局部化并且将所有与状态转换相关的行为保留在状态对象的内部。可维护性通过将每个状态转移逻辑放在单独的类中使得代码易于管理。可扩展性当需要添加新的状态时只需添加一个新的状态类不会影响到其他类。
缺点
增加系统复杂性可能会导致系统中类的数量增加。状态转移的控制如果状态转移逻辑复杂可能难以管理状态转换的顺序。
适用场景
当一个对象的行为取决于它的状态并且它的状态是可变的时。当代码需要根据对象的状态进行条件判断时。
Demo
// 环境类Context定义了客户端使用的接口并且维护一个ConcreteState子类的实例
class Context {private State state;// 设置新状态public void setState(State state) {this.state state;}// 根据当前状态执行操作public void request() {state.handle(this);}
}// 抽象状态类State定义一个接口以封装与Context的一个特定状态相关的行为
interface State {void handle(Context ctx);
}// 具体状态类ConcreteState实现State接口定义的行为
class ConcreteStateA implements State {public void handle(Context ctx) {System.out.println(Handling request in ConcreteStateA);// 根据逻辑可能需要改变Context的状态}
}class ConcreteStateB implements State {public void handle(Context ctx) {System.out.println(Handling request in ConcreteStateB);// 根据逻辑可能需要改变Context的状态}
}// 客户端代码
public class Client {public static void main(String[] args) {// 创建环境类Context context new Context();// 初始化状态context.setState(new ConcreteStateA());context.request();// 改变状态context.setState(new ConcreteStateB());context.request();}
}在这个示例中Context 是环境类它定义了客户端使用的接口并且维护了一个状态对象的实例。State 是抽象状态类定义了状态的接口。ConcreteStateA 和 ConcreteStateB 是具体状态类实现了状态接口定义的行为。
客户端代码创建了环境类的对象并且根据需要改变环境类的状态。当环境类的状态改变时它的行为也随之改变。
状态模式通过将各种状态转移逻辑分布到表示各种状态的一系列类中将对象的状态逻辑与对象本身分离。这种模式非常适合于需要根据对象状态进行条件判断的场景。
3.2.9. 策略模式
策略模式Strategy Pattern是一种行为型设计模式它定义了一系列算法并将每个算法封装起来让它们可以互换使用。策略模式让算法的变化独立于使用算法的用户用户只需要关注算法的结果而不必知道算法的实现细节。
定义 定义了一系列算法并将每个算法封装起来让它们可以互换。
优点
解耦策略模式将算法的使用从算法的实现中分离出来。可扩展性新的算法可以很容易地添加到系统中。可替换可以很容易地替换或更新现有的算法。
缺点
增加复杂性可能会增加系统中策略类的数量。性能考虑由于策略模式使用多态可能会有一些性能开销。
适用场景
当需要在运行时选择不同的处理方式时。当一个系统中有多个子系统而各个子系统有类似的行为但具体实现不同可以避免使用条件语句来决定使用哪个子系统时。
Demo
// 策略接口
interface Strategy {void execute();
}// 具体策略A
class ConcreteStrategyA implements Strategy {public void execute() {System.out.println(Executing ConcreteStrategyA);}
}// 具体策略B
class ConcreteStrategyB implements Strategy {public void execute() {System.out.println(Executing ConcreteStrategyB);}
}// 环境类
class Context {private Strategy strategy;public Context(Strategy strategy) {this.strategy strategy;}public void setStrategy(Strategy strategy) {this.strategy strategy;}public void executeStrategy() {strategy.execute();}
}// 客户端代码
public class Client {public static void main(String[] args) {// 创建环境类注入策略Context context new Context(new ConcreteStrategyA());// 执行策略context.executeStrategy();// 更换策略context.setStrategy(new ConcreteStrategyB());context.executeStrategy();}
}在这个示例中Strategy 是策略接口定义了所有支持的算法。ConcreteStrategyA 和 ConcreteStrategyB 是具体策略类它们实现了策略接口。Context 是环境类它定义了客户端使用的接口并且维护了一个策略对象。
客户端代码创建了环境类的对象并且根据需要改变环境类使用的策略。当环境类使用不同的策略时它的行为也随之改变。
策略模式通过定义算法族并将每个算法封装起来让它们可以互换使用使得算法的变化独立于使用算法的用户。这种模式非常适合于需要动态选择算法的场景。
3.2.10. 模板方法模式
模板方法模式Template Method Pattern是一种行为型设计模式它在一个方法中定义了一个算法的骨架并将一些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的情况下重新定义算法的某些步骤。
定义 定义一个算法的骨架将一些步骤延迟到子类中实现。模板方法使得子类可以不改变算法结构的情况下重新定义算法的某些步骤。
优点
代码复用模板方法模式通过提供一个通用的算法骨架允许代码复用。可扩展性通过扩展子类可以很容易地扩展新的功能。约束行为模板方法可以控制子类的扩展限制子类覆盖特定的方法。
缺点
每个不同的算法都需要一个子类实现这可能会导致类的个数增加。对于复杂的算法模板方法可能难以适应。
适用场景
当需要将一个算法分解为一系列步骤并且希望子类控制某些步骤时。当需要通过子类来实现算法的某些细节而不影响算法的整体结构时。
Demo
// 抽象模板类
abstract class Template {// 模板方法定义了算法的骨架它可能由一系列步骤组成public final void templateMethod() {step1();step2();step3();hanger();}// 钩子方法可在子类中重写但不强制protected void 钩子方法() {// 默认行为}// 这些方法是需要由子类实现的它们是具体步骤protected abstract void step1();protected abstract void step2();protected abstract void step3();
}// 具体实现类
class ConcreteTemplate extends Template {Overrideprotected void step1() {System.out.println(执行步骤1);}Overrideprotected void step2() {System.out.println(执行步骤2);}Overrideprotected void step3() {System.out.println(执行步骤3);}// 重写钩子方法Overrideprotected void hanger() {System.out.println(执行钩子方法);}
}// 客户端代码
public class Client {public static void main(String[] args) {Template template new ConcreteTemplate();template.templateMethod();}
}在这个示例中Template 是一个抽象模板类它定义了模板方法该方法是一个算法的骨架由一系列步骤组成。step1(), step2(), step3() 是需要由子类实现的抽象方法它们代表算法的步骤。钩子方法() 是一个钩子方法它提供了一个扩展点允许子类在不修改模板方法的情况下调整算法的某些细节。
ConcreteTemplate 是一个具体实现类它继承自抽象模板类并实现了所有的抽象方法以及钩子方法。
客户端代码通过创建具体实现类的实例并调用模板方法来执行算法。
模板方法模式通过定义算法骨架和延迟一些步骤到子类中实现允许子类在不改变算法结构的情况下重新定义算法的某些步骤。这种模式非常适合于实现算法的可扩展性和可重用性。
3.2.11. 访问者模式
访问者模式Visitor Pattern是一种行为型设计模式它允许在不修改对象结构的情况下添加新的操作。访问者模式通过将算法移动到对象结构之外使对象结构更容易扩展而不受算法变化的影响。
定义 表示一个作用于某对象结构中的各元素的操作它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
优点
扩展性可以在不修改对象结构的情况下添加新的操作。分离算法和对象结构使算法和对象结构分离提高灵活性。复用性访问者可以对多个对象结构进行操作。
缺点
对象结构的变化受限如果对象结构需要变化可能需要修改访问者接口和所有的具体访问者类。增加系统的复杂性引入新的访问者可能增加系统的复杂性。
适用场景
当需要对一个对象结构添加新的操作而又不想修改对象结构时。当要处理的对象结构中的对象类型比较多需要避免使用条件语句时。
Demo
// 访问者接口
interface Visitor {void visit(ConcreteElementA element);void visit(ConcreteElementB element);
}// 具体元素A
class ConcreteElementA {public void accept(Visitor visitor) {visitor.visit(this);}public void performAction() {System.out.println(Performing action on ConcreteElementA);}
}// 具体元素B
class ConcreteElementB {public void accept(Visitor visitor) {visitor.visit(this);}public void performAction() {System.out.println(Performing action on ConcreteElementB);}
}// 具体访问者
class ConcreteVisitor implements Visitor {public void visit(ConcreteElementA element) {element.performAction();}public void visit(ConcreteElementB element) {element.performAction();}
}// 客户端代码
public class Client {public static void main(String[] args) {ConcreteElementA elementA new ConcreteElementA();ConcreteElementB elementB new ConcreteElementB();Visitor visitor new ConcreteVisitor();elementA.accept(visitor);elementB.accept(visitor);}
}在这个示例中Visitor 是访问者接口定义了访问者可以进行的操作。ConcreteElementA 和 ConcreteElementB 是具体元素类它们实现了一个accept() 方法该方法接受一个访问者对象。performAction() 方法是元素执行的操作。
ConcreteVisitor 是具体访问者类实现了访问者接口中定义的所有方法。它定义了访问者如何对每一个具体元素执行操作。
客户端代码通过创建元素对象和访问者对象然后通过元素对象的accept() 方法将访问者对象传入从而执行相应的操作。
访问者模式通过将算法封装到访问者对象中使对象结构更容易扩展而不受算法变化的影响。这种模式非常适合于对象结构相对稳定但需要在其上定义新的操作的情况。
4.总结
设计模式是软件工程中用于解决特定问题的一系列最佳实践它们帮助开发者在面对常见问题时做出更好的设计决策。设计模式不是现成的代码而是一套指导原则用来指导开发者如何组织代码结构以便于更好地应对变化和提高代码的可维护性。本总结将对设计模式进行分类并提供每种模式的关键特点、优缺点、适用场景以及代码示例以帮助理解设计模式的实用性和应用方法。
4.1. 创建型模式
创建型模式关注对象的创建隐藏对象创建的复杂性提高程序的可扩展性。
单例模式确保一个类只有一个实例并提供一个全局访问点。工厂方法模式定义一个创建对象的接口让子类决定实例化哪个类。抽象工厂模式提供一个接口用于创建一系列相关或依赖的对象。建造者模式将一个复杂对象的构建与其表示分离允许通过相同的构建过程创建不同的表示。原型模式通过复制现有的实例来创建新的实例。
4.2. 结构型模式
结构型模式主要关注对象的组合通过对象的组合提高程序的模块化。
适配器模式允许将不兼容的接口转换为一个可以使用的兼容接口。桥接模式将抽象部分与其实现部分分离使它们可以独立地变化。组合模式允许将对象组合成树形结构以表示“部分-整体”的层次结构。装饰器模式动态地添加额外的功能到一个对象上而不是通过继承。外观模式为子系统中的一组接口提供一个统一的接口。享元模式运用共享技术有效地支持大量细粒度的对象。代理模式为其他对象提供一个代理或占位符以控制对这个对象的访问。
4.3. 行为型模式
行为型模式主要关注对象之间的交互描述对象如何协作以完成某种任务。
责任链模式使多个对象都有机会处理请求避免请求的发送者和接收者之间的耦合。命令模式将一个请求封装为一个对象从而允许用户使用不同的请求来参数化其他对象。解释器模式定义一个语言的文法并且建立一个解释器来解释该语言中的句子。迭代器模式提供一种方法顺序访问聚合对象的元素同时保持对象的封装。中介者模式用一个中介对象来封装一系列的对象交互。备忘录模式在不破坏封装性的前提下捕获一个对象的内部状态并在该对象之外保存这个状态。观察者模式当对象间存在一对多关系时则使用观察者模式。状态模式允许对象在其内部状态改变时改变它的行为。策略模式定义一系列算法把它们一个个封装起来并使它们可以互换。模板方法模式定义一个算法的骨架将一些步骤延迟到子类中实现。访问者模式表示一个作用于某对象结构中的各元素的操作它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
设计模式是软件设计的强大工具它们提供了一种思考和沟通架构问题的方式。掌握设计模式有助于提高代码质量促进重用以及更有效地处理复杂性。然而设计模式并不是万能的它们应该根据具体的应用场景和实际需求来选择和应用。