结构型设计模式
用于处理类或对象的组合
一、桥接模式 - Bridge Pattern
把事物对象和其具体特征分享开来,使它们可以各自独立变化。
如圆形
、三角形
归于抽象的形状
之下,而画圆
、画三角
归于实现行为的画图
之下,然后由形状
调用画图
。
桥接模式是为了实现两个接口结合的多样化而设计的一个模式。目的是为了结合的更好。
桥接模式用于设计的前期,即在设计类时将类规划为逻辑和实现两个大类,是他们可以分别精心深化。
适配器模式用于设计完成之后,当发现设计完成的类无法协同工作时,可以采用适配器模式。
然而很多情况下,在设计初期就要考虑适配器模式的使用,比如在涉及到大量第三方应用接口的情况。
- Abstraction (abstract class)抽象类
定义抽象接口,维护Implementor
的引用 - Refined Abstraction (normal class) 抽象类的普通类
抽象类Abstraction
的子类,扩展抽象定义的接口 - Implementor (interface) 实现类抽象
定义实现类的接口 - ConcreteImplementor (normal class) 实现类的普通类
实现Implementor
的接口
二、适配器模式 - AdapterPattern
适配器模式(AdapterPattern)也被称为包装样式或包装。将一个类的接口转换成用户所期待的。一个适配器使得因接口不兼容而不能在一起工作的类能在一起工作。做法是将自己的接口包裹在一个已知类中。
-
对象适配器模式
适配器容纳一个包裹的类的实例,适配器调用被包裹对象的物理实体。
-
类适配器模式
这种适配器下,适配器继承自己实现的类。
参考:维基百科https://zh.wikipedia.org/wiki/适配器模式
- 例子,方便理解
- 桥接模式
日常电器用电,用电源线(实现类的抽象)
给电器(抽象类)
和电源插座
做桥接
。 - 适配器模式
但有部分电器(如手机、电脑)并不能直接使用120V进行充电,所以中间需要再加一个充电器(电源适配器)
代码示例(Adapter 也在 Bridge 中)
https://github.com/FMR-Murphy/iOS-Design-Patterns/tree/main/桥接模式%20-%20BridgePattern
三、组合模式 - Compsite Pattern
组合模式使得用户对单个对象和组合对象的使用具有一致性。
将对象组合成树形结构以表示部分、整体
的层次结构,又叫部分整体模式
,可以用来描述整体和部分的状态。。是用于把一组相似的对象当作单一的对象。组合模式依据树形结构来组合对象,用来表示部分
以及整体
层次。这种类型的设计模式属于结构模式。它创建了对象组的树形结构。
- 一致性组合设计:(也叫
透明式组合
)所有对象都是使用同一个接口,不会区分对象之间的差别,使用者使用起来是区分不了的,树叶构件也会实现树枝构件的方法。但是是空实现,需要抛出异常。 - 安全性组合设计:树叶构件和树枝构件的接口需要区分开来,在实际使用时需要使用者区分构件类型,对于使用者来说就推动了透明性,但也不会在调用方法时抛出异常。
- Component 抽象构件
这是一个抽象角色,给参加组合的对象定义出公共的接口及其默认行为,用来约束所有的子对象。组合对象通常把它所包含的子对象当作类型为Component
的对象。在安全式的组合模式里,构建角色并不定义出管理子对象的方法,这一定义由树枝对象给出。 - Leaf 叶构件
树叶对象没有下级子对象。定义出参加组合的原始对象行为。 - Composite 树枝构件
代表参加组合的有下级子对象的对象。树枝构件类给出所有的管理子对象的方法,如add()
、remove()
以及getChild()
等。
- 例子,方便理解
文件系统就是典型的组合模式系统。
示例代码
https://github.com/FMR-Murphy/iOS-Design-Patterns/tree/main/组合模式%20-%20CompositePattern
四、外观模式 - Facade Pattern
为复杂的子系统调用提供一个统一的入口供客户端调用。使子系统更容易使用。
- Facade 外观类
为子系统中Packages1、2、3提供一个共同的对外接口。 - Clients 客户对象
通过一个外观接口访问子系统中各接口的资源。 - Packages 内部子系统
客户可以通过外观接口访问的内部子系统。
五、装饰模式 - Decorator Pattern
又叫装饰者模式。装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。
它通过创建一个包装的对象,也就是装饰来包裹真实的对象。但在不需要用到新功能的地方,它可以直接调用原来的类中的方法。装饰类必须有和原来类相同的接口。
- 例子,方便理解
- 外观模式
客厅的灯有四种状态:外圈亮、内圈亮、全亮、全灭
,本来需要一个外圈开关,一个内圈开关。但现在通过内部程序收到开关信号后循环展示四种状态,就只需要一个开关
。可以说这个开关
就是给我们的一个外观类
。 - 装饰模式
还是这个开关,过年为了喜庆,或者平时为了美观,在不使用修改内部类(拆解、激光印花等物理修改),不使用继承(更换另一个开关的“子类“)的情况下,给开关加个贴纸,动态的扩展开关的功能喜庆
。
六、享元模式 - Flyweight Pattern
使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能的相似物件。它适合用于只是因重复而导致使用无法令人接受的大量内在的大物件。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。
享元模式运用共享技术有效的支持大量细粒度的对象。
内蕴状态存储的内部,不随环境的改变而有所不同,是可以共享。
外蕴状态是不可以共享的,它随环境的改变而改变。因此外蕴状态是由客户端来保持(因为环境的变化是由客户端引起的)。
角色结构
- Client 客户端角色
维护对所有享元对象的引用,而还需要存储对应的外蕴状态。 - Flyweight Factory 享元工厂角色
负责创建和管理享元角色。要想达到共享的目的,这个角色很关键。 - Flyweight 抽象享元角色
为具体享元角色规定了必须实现的方法,而外蕴状态就是以参数的形式通过此方法传入。 - Flyweight1具体享元角色
实现抽象角色规定的方法,并存储内部状态
- 例子,方便理解
-UILabel
等显示本文的时候字体、字号、颜色等文字属性只保存一份。NSAttributedString
按索引范围Range
保存文字属性。而不是每个字都单独保存一份属性。
-常用的UITableViewCell
、UICollectionViewCell
也是享元模式。需要时从缓存池匹配现有的同类对象,如果找到就直接使用。未找到再创建新对象。
七、代理模式 - Proxy Pattern
对其他对象提供一种代理,以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理的使用可以简单地转发到真实对象,或者可以提供额外的逻辑。在代理中,可以提供额外的功能,例如,当对真实对象的操作是资源密集型时进行缓存,或者在调用对真实对象进行操作之前检查先决条件。对于客户端,使用代理对象与使用真实对象类似,因为两者都实现了相同的接口。
当一个复杂对象的多份副本须存在时,代理模式可以结合享元模式以减少存储器用量。典型作法是创建一个复杂对象,及多个代理者。每个代理者会引用到原来的复杂对象。
在 iOS 中可以使用NSProxy
实现多继承
- Subject 抽象角色
通过接口或抽象类声明真实角色实现的业务方法。 - Proxy代理角色
实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。 - RealSubject 真实角色
实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
需要与delegate进行区分
- Proxy
中介(代理)
持有若干对象(房产)
,这些对象(房产)
实现了一个共同接口(对外出租)
,客户要租房,直接找中介,中介帮我选择符合我要求的对象(房产)(在对真实进行操作之前检查先决条件)
,比每个客户都持有若干对象,挨个查看是否符合自己要求方便快捷的多。
Proxy注重过程 - delegate
任务调用和分配,注重结果,属于行为型模式,不在GoF23种设计模式之中。
客户端在合适时机把任务交给委托者(有可能是多个),委托者做不做,怎么做,都不关心。
客户委托朋友(delegate)帮忙找房,但怎么找,在哪找,找没找,具体细节都是隐藏的。