在现代软件开发中,设计模式为我们提供了优秀的解决方案,帮助我们更好地组织代码和架构。本系列专栏将对设计模式的基本思想、原则,以及常用的分类、实现方式,案例对比、以及使用建议,旨在提高开发者对设计模式的理解和应用。
文章目录
- 一、了解六大设计原则
- [二、 掌握六个类与类之间的关系](#二、 掌握六个类与类之间的关系)
- 三、设计模式的分类
- [四、 设计模式详解与对比](#四、 设计模式详解与对比)
- [五 、模式应用场景总结](#五 、模式应用场景总结)
- 六、订阅
导航图:
一、了解六大设计原则
- 单一职责原则(SRP, Single Responsibility Principle): 一个类应该只有一个引起变化的原因,避免职责混杂。
- 开放封闭原则(OCP, Open/Closed Principle): 软件实体应该对扩展开放,对修改封闭,强调通过扩展而非修改来应对变化。
- 里氏替换原则(LSP, Liskov Substitution Principle): 子类对象必须能够替换父类对象而不影响程序正确性,确保继承关系的合理性。
- 接口隔离原则(ISP, Interface Segregation Principle): 客户端不应该被迫依赖于它不使用的接口,强调小而专一的接口设计。
- 依赖倒置原则(DIP, Dependency Inversion Principle): 高层模块不应该依赖于低层模块,二者都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖于抽象。
- 迪米特法则(LoD, Law of Demeter): 一个对象应该对其他对象有最少的了解,降低系统的耦合度。
二、 掌握六个类与类之间的关系
- 依赖(Dependency): 一个类使用另一个类的实例,通常表现为方法参数或局部变量。
- 关联(Association): 一个类知道另一个类的存在,表现为成员变量(弱关联)。
- 聚合(Aggregation): 一种特殊的关联关系,表现为"整体-部分"的关系,整体和部分可以独立存在。
- 组合(Composition): 一种强聚合关系,整体负责部分的生命周期,部分不能独立于整体存在。
- 继承(Inheritance): 一个类通过继承另一个类来获得其方法和属性。
- 实现(Realization): 类与接口之间的关系,类实现接口的方法。
三、设计模式的分类
-
创建型模式 (Creational Patterns)
创建型模式主要关注对象的创建过程,旨在通过某种方式来控制对象的创建,减少代码中对对象的直接创建依赖,使得系统在需要扩展时更加灵活。常见的创建型模式包括:
- 工厂方法模式 (Factory Method)
- 抽象工厂模式 (Abstract Factory)
- 单例模式 (Singleton)
- 原型模式 (Prototype)
- 建造者模式 (Builder)
-
结构型模式 (Structural Patterns)
结构型模式关注类与对象的组合,简化并优化不同类和对象之间的关系。常见的结构型模式包括:
- 适配器模式 (Adapter)
- 装饰器模式 (Decorator)
- 代理模式 (Proxy)
- 外观模式 (Facade)
- 桥接模式 (Bridge)
- 组合模式 (Composite)
- 享元模式 (Flyweight)
-
行为型模式 (Behavioral Patterns)
行为型模式关注对象间职责的分配以及对象如何交互。它们提供了各种方式来组织和管理复杂的控制流。常见的行为型模式包括:
- 责任链模式 (Chain of Responsibility)
- 命令模式 (Command)
- 解释器模式 (Interpreter)
- 迭代器模式 (Iterator)
- 中介者模式 (Mediator)
- 备忘录模式 (Memento)
- 观察者模式 (Observer)
- 状态模式 (State)
- 策略模式 (Strategy)
- 模板方法模式 (Template Method)
- 访问者模式 (Visitor)
四、 设计模式详解与对比
设计模式分为三大类:创建型模式、结构型模式和行为型模式。为了清晰地展示每个模式的特性、适用场景及优缺点,下面用表格形式进行对比。
1、创建型模式对比
模式 | 意图 | 适用场景 | 优点 | 缺点 |
---|---|---|---|---|
工厂方法 | 定义一个创建对象的接口,让子类决定实例化哪个类。 | 当类不知道它所必须创建的对象类,或者希望子类来决定创建对象时。 | 通过将对象的创建过程交给子类,降低了与具体类的耦合。 | 难以管理复杂产品层次结构,增加了系统的复杂性。 |
抽象工厂 | 提供一个接口以创建一组相关或依赖的对象,而无需指定具体类。 | 系统要独立于产品的创建和组成部分,并且需要提供一组相关对象时。 | 符合开闭原则,增强产品族的扩展性和一致性。 | 增加系统复杂度,扩展新的产品族时需要修改所有工厂类。 |
单例模式 | 确保一个类只有一个实例,并提供一个全局的访问点。 | 控制全局共享资源,例如日志记录器、配置文件类、线程池等。 | 全局只有一个实例,节省了系统资源,避免不必要的重复实例化。 | 难以扩展,违反单一职责原则,可能导致类膨胀,难以测试。 |
原型模式 | 使用现有的实例来复制生成新对象,避免了创建开销。 | 需要大量相似对象且创建对象代价较高时,如需要频繁创建对象但初始化很复杂的场景。 | 提高对象创建效率,避免复杂的初始化过程。 | 深拷贝与浅拷贝的实现难度较大,且容易引发安全问题。 |
建造者模式 | 将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。 | 需要创建一个复杂对象,并且该对象由多个部分组成时,如车辆配置、计算机配置等。 | 分步创建复杂对象,关注构建过程,易于扩展。 | 对于简单对象,使用Builder模式可能会显得繁琐。 |
2、结构型模式对比
模式 | 意图 | 适用场景 | 优点 | 缺点 |
---|---|---|---|---|
适配器模式 | 将一个类的接口转换成客户端期望的接口,使得原本不兼容的类可以协同工作。 | 需要复用一些现有的类,但接口与现有系统不兼容时。 | 提高了类的复用性,符合开闭原则,避免修改原有代码。 | 增加了系统的复杂度,可能导致过多的适配器类。 |
装饰器模式 | 动态地给一个对象增加一些额外的职责。 | 需要在不改变原有对象的情况下,动态地为对象添加功能时,如GUI组件系统。 | 提供了比继承更加灵活的功能扩展方式,符合单一职责和开闭原则。 | 装饰器的层次关系复杂时会增加调试的难度,可能影响程序性能。 |
代理模式 | 为其他对象提供一个代理,以控制对这个对象的访问。 | 需要为复杂或昂贵的对象提供控制访问的功能时,如远程代理、虚拟代理等。 | 控制对象访问,增加了系统的安全性和灵活性,减少对象的内存消耗和性能开销。 | 增加了系统复杂性,可能影响性能,尤其是当代理链较长时。 |
外观模式 | 为子系统中的一组接口提供一个一致的接口,外观模式定义了一个高层接口。 | 为复杂的子系统提供简单的接口,减少外部系统对多个子系统的依赖时。 | 提供了一个更简单的接口,隐藏了子系统的复杂性,增强了代码的可读性。 | 外观模式不符合开闭原则,如果子系统发生变化,可能需要修改外观类。 |
桥接模式 | 将抽象部分与实现部分分离,使它们可以独立变化。 | 需要实现系统的多维度变化,如不同设备的输入方式、不同数据的存储方式。 | 提高了系统的可扩展性,减少了类之间的耦合性,增强了系统的灵活性。 | 增加了系统的复杂性,可能需要开发大量的接口和实现类。 |
3、行为型模式对比
模式 | 意图 | 适用场景 | 优点 | 缺点 |
---|---|---|---|---|
责任链模式 | 将请求的发送者和接受者解耦,使得多个对象有机会处理请求。 | 多个对象可能会处理某个请求时,且实际处理者在运行时确定。 | 请求的发送者和接受者解耦,增强系统的灵活性。 | 责任链过长会影响性能,调试时难以追踪。 |
命令模式 | 将请求封装为一个对象,使得可以使用不同的请求进行参数化。 | 需要对请求进行排队、记录日志或支持撤销/重做功能时,如事务管理系统。 | 使请求排队、撤销等操作变得灵活,提高了系统的可扩展性。 | 可能会导致命令类过多,增加系统复杂度。 |
观察者模式 | 定义对象间的依赖关系,当一个对象状态发生改变时,自动通知依赖对象。 | 一个对象的变化会影响其他对象时,如MVC模式中的数据变化通知视图更新。 | 观察者与被观察者之间松耦合,符合开闭原则,增加系统灵活性。 | 通知机制复杂时可能造成性能问题,观察者过多时难以管理。 |
状态模式 | 允许对象在内部状态发生变化时改变其行为。 | 对象的行为随状态改变而改变时,如游戏中角色的不同状态或商品的生命周期状态。 | 遵循开闭原则,减少了大量的条件判断,增加了状态行为管理的清晰性。 | 状态较多时可能导致状态类膨胀,增加代码维护难度。 |
策略模式 | 定义一系列算法,允许它们之间可以互换。 | 需要在不同的场景中选择不同的算法时,如支付系统中的不同支付方式。 | 避免了大量的条件判断语句,支持运行时的算法切换,易于扩展。 | 需要客户端了解所有策略以便选择合适的策略,可能增加客户端复杂度。 |
五 、模式应用场景总结
应用场景 | 推荐模式 |
---|---|
需要控制对象的创建 | 工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式 |
对象间需要复杂的组合关系 | 适配器模式、装饰器模式、代理模式、外观模式、桥接模式 |
系统中存在复杂行为 | 责任链模式、命令模式、观察者模式、状态模式、策略模式 |
在项目实践中,根据不同场景选择合适的设计模式,能够提高代码的可维护性、可读性以及灵活性。希望以上表格对比能够帮助开发者在具体应用中快速找到合适的模式。
六、订阅
喜欢的话可以订阅专栏:设计模式入门系列
深入了解每个设计模式如何实现,案例对比、以及使用建议!