易混淆的设计模式
1. 简单工厂、工厂方法、抽象工厂模式的区别¶
这三个设计模式都是工厂模式,但是它们的侧重点和运用场景不同。
首先,我们列出它们的定义:
- 简单工厂模式:又称为静态方法工厂模式,是由一个工厂对象决定创建哪一个产品类的实例。
- 工厂方法模式:创建一个用户创建对象的接口,让子类决定实例化哪个类。工厂方法使一个类的初始化延迟到其子类。
- 抽象工厂模式:为创建一组相关或者是相互依赖的对象提供一个接口,而不需要指定它们的具体类。
我们可以提炼一下它们的 核心定义
- 简单工厂模式:一个工厂方法创建不同类型的对象
- 工厂方法模式:一个具体的工厂类负责创建一个具体对象类型
- 抽象工厂模式:一个具体的工厂类负责创建一系列相关的对象
简单工厂模式的最大优点在于工厂类中包含了必要的判断逻辑,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。
工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现运算类,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行。你想要加功能,本来时工厂类的,而现在是修改客户端。
下面是这三种模式的UML图
2. 代理、装饰、桥接模式¶
在结构型设计模式中,结构相似且比较容易混淆的模式有代理、装饰、桥接模式。首先,我们还是列出它们的定义以及UML图。
- 代理模式:为其他对象提供一种代理以控制对这个对象的访问
- 装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更加灵活
- 桥接模式:将抽象部分与实现部分分离,使它们都可以独立地进行变化
三种模式的UML图如下:
代理模式 侧重于修改、控制对象的执行过程,也就是隐藏了对被代理对象的一些逻辑控制。
装饰模式 就是动态地加强目标对象的某些功能,避免为了某个功能而创建一个子类。
装饰模式与代理模式的共同点都是增强功能。但是代理的特点是添加逻辑控制,而装饰则是动态地添加功能。
桥接模式 的作用于代理、装饰截然不同,它主要是为了应对某个类族有多个变化维度导致子类类型急剧增多的场景。通过桥接模式将多个变化维度隔离开,使得它们可以独立变化,最后通过组合使它们应对多维变化,减少子类的数量和复杂度。
3. 外观模式与中介模式¶
外观模式在我们日常开发中肯定会遇到。因为各种SDK的设计思想基本上都是通过外观模式封装一个高层接口,用户通过这个高层接口完成各种各样的功能。
中介模式与外观模式有些类似,但是它侧重于同级类型之间的交互,通过中介对象使多个对象之间的依赖关系变为多对1。
其定义:
- 外观模式:要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。Facade模式提供一个高层次的接口,使得子系统更易于使用
- 中介模式:中介者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显作用。从而使它们松散耦合
两者的UML图如下
其实从上述的模式定义中我们就能够很清晰地发现它们的区别,外观模式重点是对外封装统一的高层接口,便于用户使用。
而中介模式则是避免多个互相协作的对象直接引用,它们之间的交互是通过一个中介对象进行,从而使得它们耦合松散,能够易于应对变化。
4. 策略与状态模式、命令模式¶
我们先看它们的定义
- 策略模式:定义一组算法,将每个算法都封装起来,并且使它们之间可以互换
- 状态模式:当一个对象内在状态改变时允许改变其行为,这个对象看起来像改变了其类
- 命令模式:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或记录请求日志,可以提供命令的撤销和恢复功能
其UML图如下所示
我们先看看策略与状态模式,它们的类图居然是一样的。虽然它们类型接口一样,但是它们的本质不一样。
策略模式重在整个算法的替换,也就是策略替换。
而状态模式则是通过状态来改变行为。
命令模式在行为上与策略模式有点类似,策略模式关注的是算法替换的问题,用一个新的算法替换旧算法,或者提供多种算法由调用者选择,算法的自由替换是它实现的重点。
而命令模式则关注的是解耦问题,如何让请求者和执行者解耦是它首先需要解决的,解耦的要求就是把请求的内容封装为一个个命令,由接收者执行。由于封装成了命令,就同时可以对命令进行多种处理。