设计模式之结构型模式

结构型模式

1.适配器模式(Adapter Pattern)

定义: 将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,也叫包装器。 分为类适配器模式和对象适配器模式。
结构图(对象适配器模式):
在这里插入图片描述

主要优点:
(1)将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无需修改原有结构。
(2)增加了类的透明性和复用性。将具体的业务实现过程封装在适配者类中,对于客户端而言是透明的;同一个适配者类可以在多个不同的系统中复用,提高了适配者类的复用性。
(3)灵活性和扩展性非常的好,通过使用配置文件,可以很方便的更换适配器,也可以在不修改源代码的情况下增加新的适配者类,完全符合开闭原则。
具体的讲,类适配器模式特有的优点: 由于适配器类是适配者类的子类,因此可以在适配器类中置换一些适配者类的方法,使得适配器的灵活性更强。
对象适配器特有的优点:
①一个对象适配器可以把多个不同的适配者适配到同一个目标。
②可以适配一个适配者的子类,由于适配器和适配者之间是关联关系,根据里氏代换原则,适配者的子类也可以通过该适配器进行适配。
主要缺点:
类适配器模式的主要缺点:
(1)对于Java,C#等不支持多重继承的语言,一次最多只能适配一个适配者类,不能同时适配多个适配者。
(2)适配者类不能为最终类,例如在Java中不能为final类,在C#中不能为sealed类。
(3)在Java,C#等语言中,目标类只能为接口,不能为类,使其使用具有一定的局限性。
对象适配器模式的主要缺点:
与类适配器模式相比,要在适配器中置换适配者类的某些方法比较麻烦。如果一定要置换掉适配者类的一个或多个方法,可以先做一个适配者类的子类,在子类中将适配者类的方法置换掉,再把子类当做真正的适配者类进行适配,这个实现过程较为复杂。
适用场景:
(1)系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码。
(2)想创建一个可以重复使用的类,用于与一些彼此之间没有太大关联的类,包括一些可以在将来引进的类一起工作。

2.桥接模式(Bridge Pattern)

定义: 将抽象部分与实现部分分离,使他们都可以独立的变化。又称为柄体模式或接口模式。
结构图:
在这里插入图片描述
主要优点:
(1)分离抽象接口及其实现部分。桥接模式使用“对象间的关联关系”解耦了抽象和实现之间固有的绑定关系。使得抽象和实现可以沿着各自的维度变化。
(2)在很多情况下,桥接模式可以取代多层继承,多层继承违背了单一职责原则,复用性较差,且类的个数比较多,桥接模式极大地减少了子类的个数,比多继承方案更好。
(3)提高了系统的可扩展性,在两个变化维度中任意变化其中一个维度,都不需要修改原有系统中的代码,符合开闭原则。
主要缺点:
(1)增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者在一开始就要针对抽象层进行设计与编程。
(2)使用的范围具有一定的局限性,桥接模式要求正确识别出系统中两个独立变化的维度,如何正确识别这两个维度也需要一定的积累经验。
适用场景:
(1)如果一个系统需要在抽象类和具体类之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使他们在抽象层建立一个关联关系。
(2)抽象部分和实现部分可以以继承的方式进行扩展而互不影响,在程序运行时可以动态的将一个抽象类的子类对象与一个实现类的子类对象进行组合,即系统需要对抽象类角色和实现类角色进行动态耦合。
(3)一个类存在两个(或多个)独立变化的维度,并且这两个(或多个)维度都需要独立进行扩展。
(4)对于那些不希望使用继承或因为多继承导致系统类的个数急剧增加的系统,使用桥接模式更加合适。

3.组合模式(Composite Pattern)

定义: 组合多个对象形成树形结构以表示具有“整体-部分”的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又称为“部分-整体”(Part-Whole)模式。
结构图:
在这里插入图片描述
主要优点:
(1)组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
(2)客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
(3)组合模式中增加新的容器构件和叶子构件都很方便,无需对现有类库进行任何修改,符合开闭原则。
(4)组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子对象和容器对象的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常的简单。
主要缺点:
在增加新的构件时很难对容器中的构建类型进行限制。(例如在某个文件夹中只能包含文本文件,使用组合模式时,不能依赖类型系统来施加这些约束,因为他们都来自于相同的抽象层,在这种情况下,必须通过在运行时进行类型检查来实现,这个实现过程较为复杂。)
适用场景:
(1)在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致性的对待他们。
(2)在一个使用面型对象语言开发的系统中需要处理一个树形结构。
(3)在一个系统中能够分离出叶子对象和容器对象,而且他们的类型不固定,需要增加一些新的类型。

4.装饰模式(Decorator Pattern)

定义: 动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。
结构图:
在这里插入图片描述
主要优点:
(1)对于扩展一个对象的功能,装饰模式不会导致类的个数急剧增加,比继承更加灵活。
(2)可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为。
(3)可以对一个对象进行多次装饰,通过使用不同的装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,从而得到功能更为强大的对象。
(4)具体构件类和具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,原有类库代码无需修改,符合开闭原则。
主要缺点:
(1)会占用更多的系统资源。使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或属性值有所不同,大量小对象的产生势必会占用更多的系统资源,在一定程度上影响系统的性能。
(2)更加容易出错,排错更加困难。装饰模式提供了一种比继承更加灵活的机制,同时也更加容易出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,比较繁琐。
适用场景:
(1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
(2)当不能采用继承的方式对系统进行扩展,或者采用继承不利于系统扩展和维护时,可以使用装饰模式。(不能采用继承的方式主要有两类:第1类是系统中存在大量独立的扩展,为支持每一种扩展或者扩展之间的组合将产生大量的子类,使得子类数目呈爆炸性增长;第2类是类已经被定义为不可继承,如Java语言中的final类)

5.外观模式(Facade Pattern)

定义: 外部与一个子系统的通信通过一个统一的外观角色进行,为子系统中的一组接口提供一个一个一致地入口,外观模式定义了一个高层接口,这个高层接口使得这一子系统更加容易使用。又叫门面模式。
结构图:
在这里插入图片描述
主要优点:
(1)客户端代码变得很简单,与之关联的对象也很少。对客户端屏蔽了子系统组件,减少了客户端所需处理的对象数目使得子系统使用起来更加容易。
(2)实现了客户端与子系统之间的松耦合关系,这使得子系统的变化不会影响到调用它的客户端,只需要调整调整外观类即可。
(3)一个子系统的修改对其他子系统没有任何影响,而且子系统内部变化也不会影响到外观对象。
(4)只是提供了一个访问子系统的统一入口,并不影响客户端直接进入子系统类。
主要缺点:
(1)不能很好地限制客户端直接使用子系统类,如果对客户端访问子系统类做太多限制则减少了可变性和灵活性。
(2)如果设计不当,增加新的子系统可能需要修改外观类的源代码,违背了开闭原则。
适用场景:
(1)当为要访问一系列复杂的子系统提供一个简单的入口时可以使用外观模式。
(2)客户端与多个子系统之间存在很大的依赖性。引入外观类可以将子系统与客户端解耦,从而提高子系统的独立性和可移植性。
(3)在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。

6.享元模式(Flyweight Pattern)

定义:运用共享技术有效的支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式。
结构图:
在这里插入图片描述
主要优点:
(1)可以极大地减少内存中对象的数量,使得相同或相似的对象在内存中只保存一份,从而可以节约系统资源,提高系统性能。
(2)享元模式的外部状态相对独立,而且不会影响内部状态,从而使得享元对象可以在不同的环境中被共享。
主要缺点:
(1)使系统的逻辑变复杂 ,因为需要分离出系统的内部状态和外部状态。
(2)为了可以使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。
适用场景:
(1)一个系统有大量相同或相似的对象,造成内存的大量消耗。
(2)对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
(3)在使用享元模式时需要维护一个存储享元对象的享元池,这需要耗费一定的系统资源,因此,在需要多次重复使用享元对象时才使用享元模式。

7.代理模式(Proxy Pattern)

定义: 给某一个对象提供一个代理,并用代理对象控制对原对象的引用。
结构图:
在这里插入图片描述
主要优点:
(1)代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度,满足迪米特法则。
(2)客户端可以针对抽象主题角色进行编程,增加和更换代理类无需修改源代码,符合开闭原则,系统具有良好的灵活性和可扩展性。
· (3)远程代理为位于两个不同地址空间的对象的访问提供了一种实现机制,可以将一些消耗资源较多的对象和操作移至性能更好的计算机上,提高系统的整体运行效率。
(4)虚拟代理通过一个消耗资源较少的对象来代表一个消耗资源较多的对象,可以在一定程度上节省系统的运行开销。
(5)保护代理可以控制对一个对象的访问权限,为不同用户提供不同级别的使用权限。
主要缺点:
(1)由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢,例如保护代理。
(2)实现代理模式需要额外的工作,有些代理模式的实现非常复杂,例如远程代理。
适用场景:
(1)当客户端需要访问远程主机中的对象时,可以使用远程代理。
(2)当需要用一个消耗资源较少的对象来代替消耗资源较多的对象,从而降低系统开销、缩短运行时间时,可以使用虚拟代理,例如一个对象需要很长时间才能完成加载。
(3)当需要控制对一个对象的访问,为不同级别的用户提供不同级别的访问权限时,可以使用保护代理。
(4)当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问这些结果时,可以使用缓冲代理,通过缓冲代理,系统无需在客户端每一次访问时都重新执行操作,只需直接从临时缓冲区获取操作结果即可。
(5)当需要为一个对象的访问(引用)提供一些额外的操作时,可以使用智能引用代理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值