1 设计模式的由来和概念
设计模式最早出现在建筑行业,是一位建筑领域的大牛,针对不同建筑物的建造方法进行了总结,针对类型相似的建筑场景,将较好的解决方案进行比较,提取了其中共性的套路规范,形成一定的设计模式。软件领域借鉴了这种思想,设计模式由GOF(Gang Of Four)四人组提出,对于不同类型的软件开发场景,总结了23种设计模式。
软件设计模式就是在进行软件开发的过程中,需要遵循的一些套路,这些套路经过了实践的检验,针对不同的设计场景,采用不同的设计模式,可以很好的解决相应的问题。
一个设计模式,解决一种问题,对于每一种设计模式,都有它自己的适用场景,所以,如果需要全面了解一种设计模式,就要从三个方面入手。第一个就是问题场景,也就软件开发中需要解决的问题。第二个是解决方法,也就是设计模式的主要内容,采用什么样的解决方案。最后就是最终效果,通过使用设计模式,问题是否得到解决,解决的情况怎么样,是不是彻底解决,还是有一定的局限等等。通过问题-方案(模式)-结果,可以比较全面的描述一个设计模式。在软件设计中,随处可见不同的设计模式,掌握设计模式,对于软件开发工作帮助很大。
2 设计模式分类
首先介绍一下23种设计模式,按照设计模式的目的来分,可以将23种模式分为建造型模式,结构型模式,行为型模式三类模式。
建造型模式主要用于创建对象,有5种创建型的设计模式,分别是工厂方法(Factory Method)模式,抽象工厂(Abstract Factory)模式,建造者(Builder)模式、原型(Prototype)模式和单例(Singleton)模式。
结构型模式主要处理类或者对象的组合,有7种结构型模式,分别是适配器(Adapter)模式、桥接(Bridge)模式、组合(Composite)模式、装饰(Decorator)模式、外观(Facade)模式、享元模式(Flyweight)和代理(Proxy)模式。
行为型模式主要用来描述类或者对象怎么交互和怎样分配职责,有11种行为型模式,分别是职责链(Chain of Responsibility)模式、命令(Command)模式、解释器(Interpreter)模式、迭代器(Iterator)模式、中介者(Mediator)模式、备忘录(Memento)模式、观察者(Observer)模式、状态(State)模式、策略(Strategy)模式、模板方法(Template Method)模式和访问者(Visitor)模式。
以下是一个表格,对各种模式进行简要的说明
GOF的23种设计模式列表
设计模式名称 |
简介 |
单例模式 (Singleton) |
确保一个类只有一个实例,并提供全局访问点。 |
工厂方法模式 (Factory Method) |
定义一个创建对象的接口,但将具体的创建延迟到子类中实现。 |
抽象工厂模式 (Abstract Factory) |
提供一个创建一组相关对象的接口,而不需要指定具体的类。 |
建造者模式 (Builder) |
将一个复杂对象的构建过程分解成多个步骤,以便于更灵活地创建对象。 |
原型模式 (Prototype) |
通过克隆现有对象来创建新对象,避免了直接使用构造函数创建对象的开销。 |
适配器模式 (Adapter) |
允许将一个接口转换成另一个客户端需要的接口,用于使不兼容的接口能够一起工作。 |
桥接模式 (Bridge) |
将抽象部分和实现部分分离,以便它们可以独立变化,提高系统的灵活性。 |
组合模式 (Composite) |
将对象组合成树形结构以表示部分-整体的层次结构,使客户端可以统一地处理单个对象和组合对象。 |
装饰者模式 (Decorator) |
动态地为对象添加额外的行为,是继承的一种替代方法,以实现更灵活的扩展。 |
外观模式 (Facade) |
为复杂系统提供一个简化的接口,以便客户端可以更容易地与系统交互。 |
享元模式 (Flyweight) |
共享大量细粒度对象以减少内存占用,适用于对象数量大而相似的场景。 |
代理模式 (Proxy) |
为其他对象提供一个代理以控制对这个对象的访问,可以实现延迟加载和权限控制等功能。 |
观察者模式 (Observer) |
定义对象之间的一对多依赖关系,当一个对象的状态发生变化时,其依赖对象会得到通知并自动更新。 |
备忘录模式 (Memento) |
在不暴露对象内部状态的情况下,捕获和恢复对象的内部状态。 |
状态模式 (State) |
允许对象在内部状态发生改变时改变其行为,使对象看起来好像修改了其类。 |
策略模式 (Strategy) |
定义一系列算法,将它们封装起来,并使它们可以互相替换,以便于根据需要动态地选择算法。 |
职责链模式 (Chain of Responsibility) |
将请求沿着处理者链传递,直到有一个处理者能够处理该请求为止。 |
命令模式 (Command) |
将请求封装成一个对象,从而使可以参数化客户端操作,队列或记录请求,并支持可撤销的操作。 |
访问者模式 (Visitor) |
将算法与其所操作的对象分离,使得可以在不修改对象结构的情况下添加新的操作。 |
中介者模式 (Mediator) |
将对象之间的通信集中在一个中介对象中,减少对象之间的直接耦合。 |
迭代器模式 (Iterator) |
提供一种方法来顺序访问聚合对象中的元素,而不需要暴露其内部表示。 |
模板方法模式 (Template Method) |
定义一个算法的框架,将一些步骤延迟到子类中实现,以允许子类改变算法的某些步骤而不改变其结构。 |
解释器模式 (Interpreter) |
定义语言的文法表示,并提供一个解释器来解释语言中的句子。 |
3 面向对象设计原则
软件设计模式都依赖于一定的设计原则,也就是软件中面向对象的设计原则和规范,旨在帮助开发人员编写高质量、可维护和可扩展的软件。
这些原则通常可以分为几个主要类别。
单一职责原则 (Single Responsibility Principle, SRP):一个类应该只有一个引起变化的原因,即一个类应该只有一个职责。这有助于保持类的简洁性和可维护性。
开放-封闭原则 (Open-Closed Principle, OCP):软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。这意味着可以通过扩展现有代码来引入新功能,而无需修改现有代码。
里氏替换原则 (Liskov Substitution Principle, LSP):子类应该能够替代其父类而不引起错误。这确保了继承关系的正确性和一致性。
依赖倒置原则 (Dependency Inversion Principle, DIP):高级模块不应该依赖于低级模块,两者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
接口隔离原则 (Interface Segregation Principle, ISP):不应该强迫客户端依赖于它们不使用的接口,接口应该小而专注。
迪米特法则 (Law of Demeter, LoD):一个对象应该对其他对象有最小的了解,只与其直接的朋友通信。这有助于减少耦合度。
合成/聚合复用原则 (Composite/Aggregate Reuse Principle, CARP):优先使用合成/聚合关系(组合)而不是继承来实现代码重用。组合关系更灵活且不会引入继承的复杂性。
4 使用设计模式的好处
在软件开发中遵循软件设计原则并自觉使用设计模式具有许多好处,这些好处有助于提高软件的质量、可维护性和可扩展性,同时降低开发过程中的风险和复杂性。
设计原则和设计模式鼓励开发人员编写更清晰、可读性更高的代码,从而提高代码质量。设计模式帮助将复杂性分解为更小的、可管理的部分,减少了系统的整体复杂性。通过遵循原则和模式,代码更容易理解、调试和维护,减少了错误修复和功能添加的难度。设计模式鼓励代码重用,使得相似的问题可以使用相似的解决方案,提高了开发效率。
通过将系统划分为模块和组件,遵循开放-封闭原则,可以更容易地扩展系统以支持新的功能或需求。使用设计原则和模式可以帮助开发人员避免一些常见的编程错误和设计缺陷。某些设计模式可以通过优化算法和数据结构来提高性能,使软件更加高效。
总之,遵循软件设计原则和使用设计模式是开发高质量、可维护且可扩展的软件的有效方法。它们有助于减少开发过程中的混乱和错误,并提供了一种有组织的方法来解决常见的设计和架构问题。