前言
这篇内容主要为面向对象设计和编程及 GoF 设计模式在微服务下面的使用。因此该篇总结不会讲述 GoF 设计模式的基本内容,只会总结面向对象设计的思想和各种设计模式具体使用的场景。因此阅读该篇文章要求读者有一定的设计模式的基础及 OOP 的思想。
面向对象设计
面向对象设计(Object-Oriented Design,OOD)方法是面向对象程序设计方法中一个环节。其主要作用是对分析模型进行整理,生成设计模型提供给 OOP 作为开发依据。OOD 包括:架构设计、用例设计、子系统设计、类设计等。架构设计的侧重点在于系统的体系框架的合理性,保证系统架构在系统的各个非功能性需求中保持一种平衡;子系统设计一般是采用纵向切割,关注的是系统的功能划分;类设计是根据通过一组对象、序列图展示系统的逻辑实现。 面向对象设计是为了解决软件问题而设计一个交互对象系统的过程。是一种软件设计的方法。
面向对象设计原则
SOLID 原则 -SRP 单一功能原则
单一功能原则(Single Responsibility Principle, SRP)规定每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。所有它的(这个类的)服务都应该严密的和该功能平行(功能平行,意味着没有依赖)。保持一个类专注于单一功能点上的一个重要的原因是,它会使得类更加的健壮。
SOLID 原则 -OCP 开闭原则
开闭原则 (Open Close Principle, OCP) 规定软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的
,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。而一般通过使用了继承的方式来实现该原则。
SOLID 原则 -LSP 里式替换原则
里氏替换原则(Liskov Substitution Principle, LSP) 是对子类型的特别定义。里氏替换原则的内容可以描述为:派生类(子类)对象可以在程序中代替其基类(超类)对象
。认为 程序中的对象应该是可以在不改变程序正确性的前提下被它的子类所替换的概念。
SOLID 原则 -ISP 接口隔离原则
接口隔离原则(Interface Segregation Principles,ISP)指明客户(client)不应被迫使用对其而言无用的方法或功能。接口隔离原则 (ISP) 拆分非常庞大臃肿的接口成为更小的和更具体的接口,这样客户将会只需要知道他们感兴趣的方法。这种缩小的接口也被称为角色接口(role interfaces)。接口隔离原则 (ISP) 的目的是系统解开耦合,从而容易重构,更改和重新部署。
SOLID 原则 -DIP 依赖倒置原则
依赖反转原则(Dependency Inversion Principle,DIP)是指一种特定的解耦(传统的依赖关系创建在高层次上,而具体的策略设置则应用在低层次的模块上)形式,使得高层次的模块不依赖于低层次的模块的实现细节,依赖关系被颠倒(反转),从而使得低层次模块依赖于高层次模块的需求抽象。
依赖反转原则的目的是把高层次组件从对低层次组件的依赖中解耦出来,这样使得重用不同层级的组件实现变得可能。
控制反转
控制反转(Inversion of Control,IoC)可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称 DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递(注入)给它。
实现控制反转主要有两种方式:依赖注入和依赖查找。两者的区别在于,前者是被动的接收对象,在类 A 的实例创建过程中即创建了依赖的 B 对象,通过类型或名称来判断将不同的对象注入到不同的属性中,而后者是主动索取相应类型的对象,获得依赖对象的时间也可以在代码中自由控制。详情可参考 控制反转。
封装,继承,多态
概念请参考 面向对象程序设计。
核心思想:
- 面向接口(基类,纯虚)开发, 而不是面向实现开发
- 优先使用组合,而不是继承(继承只使用在扩展)
- 设计目标,保障调用方代码稳定,而不是被调用方稳定
创建型设计模式
创建者,主要用于创建对象。
Singleton 单例模式
类有且仅有一个对象,用于保持对象和成员变量的状态,主要用于管理其他对象的生命周期。
Factory 工厂模式
主要用于动态对象创建。
- Simple Factory - 专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
- Factory Method - 创建一个用于创建对象的接口,让子类决定实例化哪一个类及使一个类的实例化延迟到子类中。即创建继承体系,例如创建不同子类
- Abstract Factory - 提供一个创建一系列相关或者相互依赖对象的接口,而不需要指定它们具体的类。即工厂继承体系,利用子工厂创建不同继承体系
ProtoType 原型模式
用于对象克隆(值传递,引用传递的概念理解),可用于动态克隆和继承体系的克隆。
Builder 生成器模式
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。主要用在控制创建对象的过程。
例如创建一个对象时,需要执行多个步骤,可以使用该模式控制对象步骤的调用顺序等。
结构型设计模式
类的结构设计,类的分解和定义及类结构的扩展。
其中分为四个大类:
- 类结构的封装 - Adaptor, Facade, Proxy
- 类结构的扩展 - Bridge, Decorator
- 数据结构 - 领域 - Flyweight
- 类结构组合 - Composite
Adaptor 适配器模式
将一个类的接口转换为客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。主要用于屏蔽外部变化,使外部接口统一,外部接口变化的隔离。
Facade 外观模式
面板设计模式,对内部复杂结构封装,接口封装,隔离内部复杂实现逻辑。
Proxy 代理模式
为其他对象提供一种代理以控制对这个对象的访问。Proxy 的接口和远端服务的接口一样,通过代理去做远程服务的调用,而不是直接调用,因为这样可以在代理中可以添加控制。
Bridge 桥接模式
将抽象和实现分离,面向接口开发,面向抽象编程。
例如:通用数据访问接口,通过定义好数据访问接口,即可开发,对于具体实现的是数据库,可通过继承改接口,并实现即可。
Decorator 装饰器模式
实现中又叫 Filter 或者 Interceptor。主要用于接口逻辑的扩展和被调用方逻辑扩展,即动态地给一个对象添加一些额外的职责。例如函数执行前后定义一系列 Interceptor,然后通过 Interceptor 实现逻辑扩展。
例如在处理用户登录逻辑时,对用户身份验证,访问计数或者日志记录都可以使用该模式实现。通过定义一个 BaseInterceptor 基类,然后将它关联到业务处理逻辑类中,通过继承 BaseInterceptor 然后实现不同的扩展逻辑即可。而这里可以结合工厂模式去创建 Interceptor 的对象。
Flyweight 享元模式
将小对象拼装为大对象,主要用于数据对象的组合。
Composite 组合模式
通过组合和依赖方式实现,而不用继承。实现方式为组合复用 + 委让(关联)。
行为型设计模式
行为模式涉及到算法和对象间职责的分配。它描述了对象或类之间的通信模式,刻画了在运行时难以跟踪的复杂的控制流。
- 扩展 - ChainOfResponsibility, Strategy, Command, TemplateMethod
- 解耦 - Mediator, Observer
- 数据状态 - Memento, State
ChainOfResponsibility 责任链模式
逻辑扩展,责任链调用顺序,不同责任节点间进行状态传递,通过状态的改变,实现逻辑的改变。
Strategy 策略模式
定义一系列的处理逻辑,把它们一个个封装起来,并使它们可以相互替换。可动态根据需要执行一些相应的策略。区别于责任链模式的是,它可以动态变化,而责任链模式是一个固定不可变的调用顺序。
Command 命令模式
用于指令与命令的分类管理。将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化。
例如 系统逻辑 -> 不同指令 -> 指令管理 -> 执行
TemplateMethod 模板方法模式
基类定义模板函数,定义子类函数执行逻辑。
例如当你需要实现一个类,并且需要的函数调用顺序固定,且所有子类都需要按照这个顺序执行时,可以在基类中定义函数的调用顺序,然后子类都可以调用父类的这个模板方法函数进行统一的函数调用。
Mediator 中介者模式
用一个中介对象来封装一系列的对象交互。中介者使得各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。主要用于 IOC(Inversion of Control), 服务总线。
Observer 观察者模式
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖的对象都能够得到通知并被自动更新。主要用于消息的处理,可以用在消息总线。
Memento 备忘录模式
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保持这个状态,这样就可以将该对象恢复到原先保存的状态。主要用于数据的备份还原。当需要对数据备份或者还原操作时,可是使用该模式。
State 状态模式
系统不同状态下,不同行为,继承 状态继承数, 不同行为定在状态子类中。
Visitor 访问者模式
表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
总结
GoF 23 种设计模式主要是前人基于面向对象设计及编程的思想,经过大量的实践总结出来的通用设计模式。而其中主要利用了面向对象编程的封装,继承和多态的思想, 因此想要熟练的掌握设计模式,需要熟练的掌握和理解 OOP 的思想。对于 GoF 23 中设计模式,在 OOP 的角度理解是基本相同的,而它之所以不同,是因为它们使用在不同的场景下。例如创建型设计模式则是为了对象的创建而总结的模式,结构型和行为型同样分别为类的结构和对象的行为总结的模式。而对于结构型来说,又有对类结构的封装,类结构的扩展及组合而使用的模式。同样对于行为型模式来说,也基本基于扩展,解耦及状态的而使用的模式。
因此 对于不同设计模式来说,不能片面的通过类图来理解和区别它们之间的关系。而是要在理解了各种设计模式的作用后,结合具体的场景去理解是否适合某种模式。而在真正的开发过程中,并不会只有一种设计模式的这种简单的情况,往往是多种设计模式的结合使用。例如在桥接模式下,我们需要定义一个抽象接口,因此也需要多个实现类去继承该接口,而这时,我们可以通过工厂模式去创建那些具体的实现类的对象。而同样,在具体的实现类中,我们同样可以通过装饰器模式对不同的实现类扩展不同的功能。
通过这次学习,我个人对设计模式的理解有了巨大的思想的转变。以前我都会拿着设计模式的类图去匹配需要,是否满足自己的需要,如果符合就使用它。而现在通过对每种设计模式的使用场景去思考是否使用该模式。 例如 Adaptor 模式和 Proxy 模式,个人以前不是很理解这两种的区别,它们都是结构型的,都说是封装,因此总感觉它们都是一样的。但是现在从它们使用场景不同,可以很好地区分它们,因为 Adaptor 是对外部接口的隔离,而 Proxy 模式则是代理远端服务的功能。结合了公司当前代码来理解,确实是这样,我们对于第三方源码的封装则使用的是 Adaptor,而对于外部服务的访问封装则叫 XXProxy。