结构型模式总结
前言
到今天为此,我们已经完成了对所有结构型模式的介绍和学习,如果大家都对每一篇博文都仔细浏览查看的话,相信对七种结构型模式会有一个更深层次的掌握和理解,与此同时,在每一篇博文中,我们都针对当前介绍的模式与其他相关模式进行了对比,剖析了各自的异同点和关联性,使得大家可以从纵、横两方面更好地领悟各个模式精髓,而不仅仅只是局限于对单个模式的介绍。所谓纵维度比较指的是不同类型模式间的比较,在设计模式中主要分为三类:创建型、结构型和行为;而横维度比较指是在相同类型模式间的比较,因为是同类型,相较而言有更多的相同处,但是此时能明白无误地辨别彼此间的差异点更显重要。因为本篇博客是对结构型模式的总结,所以接下来,我们将重点对各个结构型模式意图以及它们彼此的相关性进行概要的总结,加深大家对结构型模式的整体认识。
概述
结构型模式主要用于描述如何组合类和对象以获得更大的结构。其中,结构型类模式采用继承机制来组合接口和实现,而结构型对象模式则采用组合/聚合方式来组合对象以实现新功能,因为它可以在运行时刻改变对象组合关系,所以对象组合方式具有更大的灵活性,这种机制是无法通过静态类组合来实现的。当然两者都有彼此擅长之处,具体的取舍需要根据实际的应用场景而定。我们介绍过的结构型模式总共有七种,简写为:ABCDFFP(Adapter,Bridge,Composite,Decorator,Façade,Flyweight,Proxy),也就是对应的的适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。从之前对以上七种结构型模式的介绍里,我们了解到优先使用对象组合,而不是类继承原则在结构型模式中得到淋漓尽致的体现,当然并不是说不能使用继承方式,毕竟类继承可是面向对象的三大特性之一(多态、继承和封装)。应该说继承是随便可见的,但是每一种继承只适合于封装一种变化,面对多维变化场景时,如果仍强行使用多继承方式来实现,必然会造成子类数目成“爆炸性”增长问题,这方面叙述在桥接模式和装饰器模式中都有很好的体现。比如在桥接模式中,通过简单的继承方式并不能很好地处理抽象化与实现化都独立变化的情况,但是通过对象组合的方式却可以很好地应对这方面需求,使多维变化点能够独立地扩展和变化。
模式区别比较
首先让我们先大致浏览下所有结构型模式的主要作用吧!
- 适配器模式:将一个类的接口转换成客户希望的另外一种接口,这样就能实现已有接口的复用。适配器主要有类适配器和对象适配器两种实现方式,通常情况下,推荐优先使用对象适配器方式。
- 桥接模式:将抽象部分与实现部分分离,使它们都可以独立地变化。它主要用于应对多维度变化点问题,通过对象组合的方式,可以极大地减少子类的数目,同时还能让不同维度独立扩展变化。
- 组合模式:将对象组合成树形结构以表示“整合-部分”的层次结构,从而使得用户对单个对象和组合对象的使用具有一致性,也就是客户端能够透明地无区别地操作两者。
- 装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更为灵活。假若使用多继承的方式来完成职责的添加,将会不可避免地造成子类数目的“爆炸性”增长,此外,因为是静态增加的,那也就不可能在运行状态时动态地添加或者删除额外职责呢。
- 外观模式:为子系统中的一组接口提供一个一致的接口,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。这样原来需要客户直接与复杂的子系统打交道、交互,现在这一过程将完全将交由外观对象来完成,极大地方便了客户端的调用。
- 享元模式:运用共享技术有效地支持大量细粒度的对象。享元模式关键是将对象的内部状态和外部状态分离,尽可能地对“稳定”的内部状态进行共享,而将会随运用场景而改变的状态通过外部状态传入。
- 代理模式:为其他对象提供一种代理以控制对这个对象的访问。主要是在客户端和目标对象间增加一层间接层,通过这个间接层来完成对目标对象的种种控制操作,所以也就形成了不同功能类型的代理呢,比如远程代理、保护代理和虚代理等等。
完成了对所有结构型模式的意图介绍,现在我们通过对比的方式来进一步加深对各个结构型模式的认识,同时也能进一步理解结构型模式间的关联和区别点。
- 装饰模式与桥接模式:两者从某种意思上来说都是通过对象组合的的方式来避免功能子类数目的急剧增长,但是两者解决之道却各有特点。装饰模式是将子类中较基类中多出来的功能部分放到单独的类中,以满足对基类新功能添加的需要,将不同的功能(职责)封装成一个个独立地装饰类,这样当各种不同的功能类组合到基类中时,就可以较好地完成基类对新功能的要求,也就相当于是一个增加的功能子类呢。而桥接模式是通过将基类的实现化部分抽象出来,形成一个独立的实现结构,同时也将基类部分构建成一个抽象化的等级结构。如此,抽象化部分和实现化部分就可以在各自的维度上独立地发生变化和扩展,通过桥接的方式将两者关联,简单地说就是抽象化部分保留一个实现化部分的引用,在需要的时候方便调用。下面是装饰模式与桥接模式的简单结构对比图:
- 外观模式与代理模式:两者解决的问题侧重点不一样,但是解决问题的思路是一致的,都是通过引进一层间接层,这样的解决方式在软件开发时经常使用到。外观模式主要用于简化接口,但是外观也完全可以同代理模式结合使用,因为外观对象完全可以是一个位于远程地址空间对象的远程代理,简称为外观代理模式或者说是代理外观模式,下面是外观模式和代理模式的简单结构对比图:
- 适配器模式:其主要是目的是转换接口,完成类库复用或者代码迁移等工作,是一种“事后解决之道”——亡羊补牢。主要有两种适配器模式,类适配器和对象适配器,需要根据实际的应用环境来选用两者其中之一。但一般情况下建议优先使用对象适配器,这样可以避免多继承方式的各种弊端,下面是两种类型的适配器模式简略图:
结束语
本文对所有结构型模式做了一次简单的总结,其中还对若干组结构型模式进行了横向比较,希望能让大家对结构型模式整体上有一个全方位的理解和认识。当然,如果需要深入地学习具体的模式,建议大家还是浏览查看之前对各个结构型模式的具体介绍的相关博文,相信在那里,大家会对各个具体结构型模式有一个更为全面和深刻的认识。对结构型模式的总结就简单地介绍到这里呢,从下一篇开始,我们将正式开始学习最后一种类型的设计模式——行为型模式,相较而言,行为模式种类繁多,也较难懂,但是只要怀着一股坚韧的学习之心,相信大家最终会对它们有更深层次的理解和认识,敬请期待!
参考资料:
- 程杰著《大话设计模式》一书
- 陈臣等著《研磨设计模式》一书
- GOF著《设计模式》一书
- Terrylee .Net设计模式系列文章
- 吕震宇老师 设计模式系列文章