结构型设计模式
结构型模式关注于整体最终的结构,通过继承和组合,构建出更加复杂的结构
进而提供更加强大的逻辑功能
七种结构型模式
- 适配器模式(Adapter Pattern)
- 组合模式(Composite Pattern)
- 装饰器模式(Decorator Pattern)
- 代理模式(Proxy Pattern)
- 桥接模式(Bridge Pattern)
- 外观模式(Facade Pattern)
- 享元模式(Flyweight Pattern)
所有的结构型设计模式在逻辑上都各自不同程度的隐含了“间接”“代理”“委托”的含义 ,有的明显,有的含蓄
强表现
适配器、装饰器、代理、组合、桥接模式,这几种模式比较强烈的表现了“间接”“代理”“委托”的含义
从图中可以清楚地看得出来,他们都有“代理”的含义
适配器模式,通过继承或者组合方式,“代理”了,被适配角色Adaptee
装饰器模式,通过组合的方式,"是你还有你",内部拥有Component,代理了被装饰的具体构建 ConcreteComponent
代理模式,通过组合的方式,内部拥有RealSubject,代理了真实主题角色
组合模式,通过组合的方式,内部包含叶子节点或者树枝节点,内部“代理”了 子对象
桥接模式,通过组合的方式,内部拥有Implementor,指向实现者
如果装饰器模式只有一个被装饰的类ConcreteComponent,也只有一个装饰器角色ConcreteDecorator
省略掉Decorator ,他跟代理模式的结构可以说是一样的
省略掉装饰器模式结构图中的ConcreteDecorator角色,组合模式和装饰器模式的结构就完全一样了
如果只有一种类型的ConcreteImplementor,桥接模式又与对象适配器模式相同
虽然说他们都有“代理”的含义,但是他们又有很大差别
适配器模式下,“代理”的对象是功能相近的替代方案
比如,插座适配器可以进行插头转换
使得原本不兼容,不能够一起工作的那些类能够一起工作
代理模式下,“代理”的真实主题的对象RealSubject,从而对真实对象进行隐藏,封装透明的对外界提供服务,控制外界对这个对象的访问
装饰器模式下,“代理”的是抽象的Component构建,能够代理所有的ConcreteComponent类型
装饰器和被装饰的构建都是Component,重点在于功能的扩展,添加额外的职责
组合模式下,“代理”的是抽象构建Component,代理的是子对象,用于描述“整体-部分”的概念
桥接模式,“代理”的是实现角色Implementor,代理的是具体的实现,用于将抽象与实现进行分离
分离后通过桥接模式进行连接
他们虽然都是“代理”,但是他们的侧重点不同,被代理的事物的性质不同
适配器模式在代理的过程中,重点在于适配,不会增加额外的功能
代理模式侧重于控制,当然也通常用于增加功能
如果代理模式,代理的不是真实主题对象RealSubject,而是抽象构建Subject,显然,就演化成了装饰器模式
因为代理模式不光能够控制外界对真实对象的访问,他也能够提供额外的服务
装饰器模式则是重点在于功能的扩展,增肌额外的职责
而组合模式,重点在于形成“整体--部分”的结构,并且对外界客户端程序,提供一致的访问形式
弱表现
享元模式和外观模式也是一定程度的代理
享元模式,通过内部状态与外部状态的分离,通过享元池中的享元对象,代理了所有的具有内外状态完整的对象
对客户端来说就是有如此多的对象, 只不过内存中却仅有少量的对象
外观模式在结构上完全看不出来“代理”的含义,但是他在业务逻辑上充当的也恰恰是“接口人”“协调者”“控制台”的角色
所以也可以认为是“代理”了内部的子系统
代理模式与适配器模式
代理模式和适配器模式都需要借助于内部的“被代理”对象,或者“被适配者”对象进行工作
也就是说他们都将自己的工作委托出去
但是代理模式中,代理者与被代理者他们拥有相同的接口,也就是拥有相同的对外呈现,重点在于对真实对象的隐藏,客户端请求的透传,并且可以额外的增加一些控制,管理
适配器模式中,目标对象和被适配者在接口上没有必然联系,比如目标是港版插座面板,被适配者是大陆插座面板,他们的共同点是提供电力,但是接口却完全不同
适配器的重点在于不能一起工作的类能够一起工作
代理模式与装饰器模式
代理模式提供与被代理的真实对象相同的访问接口,对真实对象进行一定的控制,也可以增加额外的服务,职责
装饰器模式也是代理了内部真实的对象,并且拥有相同的访问接口
但是代理模式重点在于增加对真实对象的控制,隐藏真实对象,一般会在代理类内部创建一个真实的对象
也就是说这种代理关系在编译时期已经静态确定了
代理类接受处理来自客户端的请求,在内部转发到真实主题对象上
比如
//代理模式
public class Proxy implements Subject{
private Subject realSubject;
public Proxy(){
//关系在编译时确定
realSubject = new RealSubject();
}
public void doSth(){
….
realSubject.doSth();
….
}
}
装饰器模式在于功能的动态增加,所以对象一般作为参数进行传递,比如:
InputStream inputStream = new BufferedInputStream(new FileInputStream("........"));
这是一种在运行期间动态增加功能方式
适配器与外观模式
适配器模式将一种接口转换为另外一种接口,使得原本不能一起工作的类可以协作
外观模式是将子系统的的多个接口的访问转换为另一种接口,使得原本复杂难用,耦合程度高的多个类有一个一致简单的接口
他们都变成了另外一种形式的接口
所有的请求也都是委托他人进行处理,适配器模式委托给被适配角色,外观模式委托给子系统
适配器模式是为了能够一起工作,他们原本是并不兼容的
外观模式是为了能够更好地更简单的工作,他们原本是可以一起工作的
桥接模式与适配器模式
适配器模式的主要目的是让因为接口不兼容而不能互相工作的类能够一起工作
换句话说就是他们本身不同,我用“纽带” Adapter将他们连接起来
而桥接模式则是将原本或许紧密结合在一起的抽象与实现,进行分离
使她们能够各自独立的发展,是把连接在一起的两个事物,拆分开来
然后用“纽带”“桥梁”(也就是对象的引用)将他们连接起来
适配器模式就好比张三和王五不认识,李四介绍他们认识
桥梁模式好比张三和王五成天黏在一起活干得不好太乱套,李四说以后我作为接口人,你俩各干各的吧
虽然看起来都是两个人干活,中间一个联系人,但是含义却是完全不同
桥接模式与装饰器模式
装饰器模式中,使用组合而不是继承来对类的功能进行扩展
避免了类的个数的爆炸增长,与桥梁模式的结果不约而同
他们都解决了类爆炸增长的问题,都避免了过多的没必要的子类
装饰器模式侧重于功能的动态增加,将额外的功能提取到子类中
通过不同的排列组合,形成一个递归的调用方式,以动态的增加各部分的功能
桥梁模式是将原本系统中的实现细节抽取出来,比如原来抽象概念与实例化全部都是一个类层次结构中
把所有的实现细节,比如示例中的平台相关实现,抽取出来,进行分离,达到抽象与实现分离的目的
所以虽然他们都可以解决子类爆炸式增长、不易扩展的问题
但是他们的出发点完全不同
一个关注于功能的动态扩展组合
一个关注于抽象与实现的分离,获得更多的灵活性
总结
所有的结构型模式的都离不开“分离,解耦”的概念
而“分离,解耦”之后,又通过某种形式建立联系,比如“组合”
抽象与实现进行分离,分离就意味着独立,独立就意味着可以单独发展,桥接模式
对于分离的事物通过委托的形式托付工作,就可以在中间提供更多的服务,代理模式
而分离的两个事物也可以通过一定形式的结合、转换进而一起协同工作,适配器模式
将一个对象的多个功能点进行分离,从而能够动态的组合以形成更强大的功能,装饰器模式
将事物自身内部核心状态与外部状态进行分离,进而减少核心状态的存储运行消耗,享元模式
将客户端与子系统的耦合交互进行分离,抽象出来一个新的接入点,外观Facade,降低耦合,外观模式
分离开的多种事物,如果他们有“整体--部分”的关系,可以将它们组合在一起,形成更复杂的整体结构,组合模式
(ps:上面的分离指分开的,不耦合在一起,不是特指原本是一个整体,被分成两部分)
以上各个部分的差异对比点主要根据设计模式的最初意图、动机,设计模式本就是设计原则的实现化角色
对于任何的结构,你都可以按照你自己的想法去使用、拓展,当然,前提是更合适或者更优秀
否则您那是瞎用
比如代理模式与装饰器模式本就很类似,如果你将代理模式的真实对象也是作为参数进行传递
也是用来动态的增加职责,那么就成了装饰器模式,所以再回头,你说你的是代理模式还是装饰器模式?
这么看这个名字代理还是装饰器又有什么大的区别的呢?都只是用来叙述而已
但是如果你这么做还非要说是代理模式,有一个很大的问题就是和同事、领导沟通起来就特别费劲了,说不定还会吵起来...
所以,除非你有更好更合适的选择,或者改变
否则,一定要尽量按照模式原本的意图和动机去使用某种模式
转载务必注明出处:程序员潇然,疯狂的字节X,https://crazybytex.com/thread-115-1-1.html