设计模式是一种解决常见编程问题的经验总结,提供了代码的可重用性、可扩展性和可维护性。常见的设计模式有23个,主要分为三大类:创建型模式、结构型模式和行为型模式。下面是这三类设计模式的详细分类和讲解:
一、创建型模式
创建型模式主要处理对象的创建过程,提供了不同的方式来控制对象的创建,以提高灵活性和可复用性。
1. 单例模式(Singleton Pattern)
保证一个类仅有一个实例,并提供全局访问点。
- 使用场景:资源管理器、日志系统、数据库连接池等。
- 优点:减少内存开销,避免多次创建实例。
- 缺点:容易造成全局状态,使得代码难以测试。
2. 工厂方法模式(Factory Method Pattern)
定义一个用于创建对象的接口,但让子类决定要实例化的类。
-使用场景:当一个类不知道它所需要创建的对象的具体类型时。
-优点:提高灵活性,使代码依赖于抽象而非具体类。
-缺点:增加类的数量,增加系统复杂性。
3. 抽象工厂模式(Abstract Factory Pattern)
提供一个接口,用于创建一系列相关或依赖的对象,而无需指定具体的类。
-使用场景:当系统需要与多个相关联的产品族打交道时。
-优点:易于扩展,满足"开放-关闭"原则。
-缺点:复杂度较高,扩展困难。
4. 建造者模式(Builder Pattern)
将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
- 使用场景:构建复杂对象时,如HTML生成器、SQL查询构建器等。
- 优点:使得创建过程更加清晰,可拆分步骤。
- 缺点:产品变化多时,建造者类可能会变得庞大。
5. 原型模式(Prototype Pattern)
通过复制已有的实例来创建新对象,而不是通过实例化类来创建。
- 使用场景:当对象的创建开销较大,且需要大量相似对象时。
- 优点:避免重复初始化。
- 缺点:深拷贝和浅拷贝的处理可能较复杂。
二、结构型模式
结构型模式关注类和对象的组合,主要目的是通过继承或组合的方式来获得新的功能。
1. 适配器模式(Adapter Pattern)
将一个类的接口转换成客户希望的另外一个接口,使得原本接口不兼容的类可以一起工作。
- 使用场景:当现有类的接口与需求不符时,如将老系统接口适配新系统。
- 优点:复用已有代码,增强代码兼容性。
- 缺点:增加了系统的复杂性。
2. 桥接模式(Bridge Pattern)
将抽象部分与实现部分分离,使它们可以独立变化。
- 使用场景:当一个类具有多个维度的变化时(如设备和操作系统)。
- 优点:可以独立扩展抽象和实现部分。
- 缺点:增加了系统的理解和设计难度。
3. 组合模式(Composite Pattern)
将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
- 使用场景:当系统需要表示树形结构时,如文件系统。
- 优点:简化了客户端代码。
- 缺点:使得设计更加复杂。
4. 装饰器模式(Decorator Pattern)
动态地给对象添加新的功能,而不改变其结构。
- 使用场景:需要动态地为对象增加功能,如给窗体增加滚动条。
- 优点:灵活性高,不改变原有类的情况下扩展功能。
- 缺点:增加了系统的复杂性。
5. 外观模式(Facade Pattern)
提供一个统一的接口,来访问子系统中的一群接口,使得子系统更加容易使用。
- 使用场景:当系统复杂,且需要对外提供简化的接口时。
- 优点:简化了复杂系统的调用,降低了客户对子系统的依赖。
- 缺点:可能掩盖了子系统的真正复杂性。
6. 享元模式(Flyweight Pattern)
通过共享已经存在的对象,减少创建对象的数量,从而减少内存开销。
- 使用场景:大量相似对象存在,且内存占用大时,如文本编辑器中的字符对象。
- 优点:减少内存消耗,提高性能。
- 缺点:增加了系统复杂性。
7. 代理模式(Proxy Pattern)
为其他对象提供一种代理,以控制对这个对象的访问。
- 使用场景:远程代理、虚拟代理、保护代理等场景。
- 优点:控制访问权限,降低开销。
- 缺点:引入了间接性,增加了复杂度。
三、行为型模式
行为型模式关注对象之间的通信和协作,目的是使对象之间的交互更加灵活。
1. 责任链模式(Chain of Responsibility Pattern)
将请求沿着处理链传递,直到有一个对象处理它。
- 使用场景:需要多个对象处理请求,但处理者不确定时。
- 优点:降低了请求发送者和接受者之间的耦合度。
- 缺点:处理链过长时,性能可能受到影响。
2. 命令模式(Command Pattern)
将请求封装成对象,以便可以使用不同的请求、队列或日志来参数化其他对象。
- 使用场景:实现撤销操作、事务管理等。
- 优点:解耦请求发送者和接收者。
- 缺点:增加了系统的复杂性。
3. 解释器模式(Interpreter Pattern)
给定一种语言,定义它的文法表示,并定义一个解释器来解释这些表达式。
- 使用场景:编译器、规则引擎等。
- 优点:灵活,易于扩展文法。
- 缺点:文法复杂时,难以维护。
4. 迭代器模式(Iterator Pattern)
提供一种方法顺序访问一个集合对象中的各个元素,而不暴露其内部表示。
- 使用场景:遍历集合对象时。
- 优点:使得集合遍历统一。
- 缺点:额外的开销。
5. 中介者模式(Mediator Pattern)
通过一个中介者对象来封装对象之间的交互,使得对象不需要显式地相互引用,降低了耦合度。
- 使用场景:多个对象间交互复杂时,如GUI组件之间的通信。
- 优点:减少了对象之间的依赖关系。
- 缺点:中介者本身可能会变得复杂。
6. 备忘录模式(Memento Pattern)
在不破坏封装的前提下,捕获对象的内部状态,以便在未来可以恢复它。
- 使用场景:实现撤销操作时。
- 优点:实现了对象状态的快照。
- 缺点:可能导致内存开销大。
7. 观察者模式(Observer Pattern)
定义对象间的一对多依赖关系,当一个对象状态改变时,所有依赖它的对象都会得到通知并自动更新。
- 使用场景:事件监听机制,GUI框架等。
- 优点:松散耦合,灵活性高。
- 缺点:如果观察者太多,通知可能会导致性能问题。
8. 状态模式(State Pattern)
允许对象在其内部状态发生改变时改变其行为,看起来像是修改了它的类。
- 使用场景:对象的行为随状态变化而变化时,如状态机。
- 优点:将状态与行为封装在一个类中,减少条件语句。
- 缺点:状态较多时,类的数量可能会增加。
9. 策略模式(Strategy Pattern)
定义一系列算法,并将它们封装起来,使它们可以互相替换,且算法的变化不会影响使用算法的客户。
- 使用场景:当算法有多种实现方式
- 优点:符合"开放-关闭"原则,易于扩展。
- 缺点:客户端需要了解不同的策略类。
10. 模板方法模式(Template Method Pattern)
定义算法的骨架,并允许子类在不改变算法结构的情况下重新定义某些步骤。
- 使用场景:固定算法流程,但部分步骤需要可扩展时。
- 优点:复用代码,易于维护。
- 缺点:灵活性受限。
11. 访问者模式(Visitor Pattern)
访问者模式用于将数据结构与操作解耦。通过在访问者中定义新的操作,可以避免修改数据结构。该模式允许你在不改变元素类的前提下,定义作用于这些类的新操作。
- 使用场景:需要对一个对象结构中的元素执行许多不同的操作,但又不希望因为频繁增加新操作而修改这些类时。
结构:访问者模式有两个关键角色: - 优点:增加新的操作非常简单,只需增加新的访问者类即可。符合单一职责原则,将不同操作的实现与对象结构的实现分离。
- 缺点:如果对象结构经常改变,添加新元素会比较麻烦,因为所有的访问者类都需要更新。
这些设计模式是软件开发中常用的工具,通过合理的使用可以显著提高系统的灵活性、扩展性和可维护性。在实际开发中,选择合适的模式需要根据具体问题场景来判断。
参考文档
https://medium.com/nerd-for-tech/design-patterns-introduction-7022b8d384c6