3.桥梁模式
桥梁模式:桥梁模式是一个非常重要的模式,也是一个比较复杂的模式。熟悉这个模式对于理解面向对象的设计原则,包括“开-闭”原则(OCP)以及组合/聚合复用原则(CARP)很有帮助。
桥梁模式的用意是“将抽象化与实现脱耦,使二者可以独立地变化”。
(1)抽象化 存在于多个实体中的共同概念性联系,就是抽象化。
(2)实现 即针对抽象化给出的具体实现
(3)脱耦 耦合是指两个实体行为的某种强关联。如果将他们的强关联去掉,就被称为耦合的脱耦,或者称为解耦。脱耦是指将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改成弱关联。
桥梁模式中涉及如下4个角色:
1.抽象化角色(Abstraction):抽象化给出的定义,并保存一个对实现化对象的引用。
2.修正抽象化(RefinedAbstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
3.实现化角色(Implementor):这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定与抽象化角色接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
使用桥梁模式的场景:例如公司内部的OA系统如果有尚未处理完毕的文件,则需要发送一条消息进行提示。从业务上看,发送的消息可以分为普通消息、加急消息和特急消息多种。不同的消息类型,业务功能处理是不一样的,比如加急的消息是在消息上添加加急,而特急消息除了添加加急外,还会做一条催促记录,多久不完成会继续催促;从发送消息的手段上看,又有系统内短消息、手机短消息、邮件等。
使用桥梁模式来解决问题:
根据业务的功能要求,业务的变化具有如下两个维度。
1.抽象的消息:包括普通消息、加急消息和特急消息。这几个抽象的消息本身就具有一定的关系,加急消息和特急消息会扩展普通消息。
2.具体的消息发送方式:包括系统内短消息、邮件和手机短消息,这几个方式是平等的、可被切换的方式。
现在出现问题的根本原因是因为消息的抽象和实现是混杂一起的,这就导致了一个维度的变化会引起另一个维度进行相应的变化,从而使得程序扩展起来非常困难。
抽象部分是各个消息的类型所对应的功能,而实现部分是各种发送消息的方式。按照桥梁模式的结构,给抽象部分和实现部分分别定义接口,然后分别实现它们就可以了。使用桥梁模式来实现这些功能的程序结构如图:
4.组合模式
组合模式:组合模式体现了部分与整体的关系,其典型的应用就是树形结构。组合涉及的是一组对象,其中有对象可能含有其他的对象,因此有的对象可能代表一个对象群组,而有的就是单个对象,即叶子。
组合模式中的主要构成元素如下:
Component类,组合中的对象声明接口,在适当情况下,实现所有类共有接口的行为。声明一个接口用于访问和管理Component的子部件。
Leaf类:叶节点对象。叶节点没有子节点。由于叶节点不能增加分支和树叶,所以叶节点的Add和Remove没有实际意义。叶节点行为用来存储叶节点集合。
Composite类:实现Component的相关操作,比如Add和Remove操作。
组合模式涉及如下几个角色:
(1)抽象构件(Component)角色:这是一个抽象角色,它给参加组合的对象规定一个接口。这个角色给出共有的接口及其默认行为。
(2)树叶构件(Leaf)角色:代表参加组合的树叶对象。树叶没有下级的子对象。定义出参加组合的原始对象的行为。
(3)树枝构件(Composite)角色:代表参加组合的有子对象的对象,并给出树枝构件对象的行为。
实现逻辑树:
5.装饰模式
装饰模式:装饰模式是指给一个类添加一些额外的职责,并且在添加这些额外的职责时不会控制该类的执行逻辑。装饰模式能够在不改变原类文件和使用继承的情况下,动态扩展一个对象的功能。装饰模式是一个通过创建一个包装对象来实现的,也就是用装饰来包裹真实的对象。
装饰模式的特点:
1.装饰对象和真实对象有相同的接口。这样客户端对象就能够以真实对象相同的方式同装饰对象交互。
2.装饰对象包含一个真实对象的索引。
3.装饰对象接收所有的来自客户端的请求。它把这些请求转发给真实的对象。
4.装饰对象可以在转发这些请求以前或以后增加一些附加的功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。
装饰模式与类继承的主要区别:
1.装饰模式是一种动态行为,对已经存在的类进行随意组合,而类的继承是一种静态行为,一个类定义成什么样,其对象便具有什么样的功能,无法动态地改变。
2.装饰模式扩展的是对象的功能,不需要增加类的数量。而类继承扩展是类的功能,在继承的关系中,如果我们想增加一个对象的功能,我们只能通过继承关系,在子类中增加两个方法。
3.装饰模式是在不改变原类文件和使用继承的情况下,动态地扩展一个对象的功能,它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
4.装饰模式把对客户端的调用委派给被装饰的类,装饰模式的关键在于这种扩展是完全透明的。
具体实例:加入计算机系的某个漂亮的MM要过生日了,我决定送个蛋糕作为生日礼物。市面上的蛋糕多种多样:巧克力、冰淇淋、奶油等。另外在加点额外的装饰,例如在蛋糕里放花、放贺卡、放干果。可以把蛋糕作为一个抽象类,让剩下的蛋糕子类型来继承它,每个子类都有吃该蛋糕的感觉。蛋糕的子类分别是奶酪蛋糕、巧克力蛋糕、冰淇淋蛋糕、插花的冰淇淋蛋糕、放贺卡的冰淇淋蛋糕。
某MM喜欢带花的冰淇淋蛋糕,还好我早有准备。但是有几次失策了,她们要的蛋糕我这里都没有,比如带鲜花的巧克力蛋糕、带果仁的牛奶蛋糕、带鲜花带果仁的蛋糕等。
看来还得继续添加蛋糕的子类,这是问题出现了,这样会造成大量的蛋糕子类。
其实真正要关注的是蛋糕,而贺卡、花、果仁等只不过是起到了装饰的作用。现在以蛋糕为主体,其他的东西都加到蛋糕上。MM要什么样的,我就加什么。
到现在为止,要明确的是:
蛋糕是主体,花、贺卡、果仁等是装饰者。可以用装饰者包装蛋糕。
6.外观模式
外观模式:外观模式也被称为Facade模式,能够为子系统中的一组接口提供一个统一的接口。 Facade模式定义了一个更高层的接口,使子系统更加容易使用。外观模式是一种结构型模式,它主要解决的问题是:组件客户和组件中各种复杂的子系统有了过多的耦合,它主要解决的问题是:组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化挑战。
在真实的应用系统中,一个子系统可能由很多类组成。子系统的客户为了满足他们的需要,需要与子系统中的一些类进行交互。客户和子系统的类进行直接的交互会导致客户端对子系统之间的高度耦合。
外观模式为子系统提供了一个更高层次、更简单的接口,从而降低了子系统的复杂度和依赖,这使得子系统更易于使用和管理。外观是一个能为子系统和客户提供简单接口的类。当正确第应用外观时,客户不再直接与子系统中的类交互,而是与外观交互。外观承担与子系统中类交互的责任。实际上,外观时子系统与客户的接口,这样外观模式降低了子系统和客户的耦合度。
外观模式也是由代理模式发展而来的。与代理模式类似,代理模式是一对一的代理,而外观模式是一对多的代理。与装饰模式不同的是,装饰模式为对象增加功能,而外观模式则是提供一个简化的调用方式。一个系统可以有多个外观类(门面类),每个门面类都只有一个实例,可以使用单例模式来实现。
在外观模式下包含如下角色:
1.门面角色(Facede):这是门面模式的核心。它被客户角色调用,因此它熟悉子系统的功能。它内部根据客户角色已有的需求预定了几种功能组合。
2.子系统角色(SystemA、SystemB、SystemC):实现了子系统的功能。对子系统角色来说,facade角色与客户一样,是未知的,它没有任何facade角色的信息和连接。
3.客户角色:调用facade角色来完成要得到的功能。
7.享元模式
享元模式:享元模式即FlyWeight模式,是构造型模式之一,通过与其他类似对象共享数据来减小内存的占用情况。享元模式运用共享技术有效地支持大量细粒度的对象,也就是说,在一个系统中如果有多个相同的对象,那么只需要共享一份即可,而不必去实例化每一个对象。
享元模式所涉及的角色有抽象享元角色、具体(单纯)享元角色、复合享元角色、享员工厂角色,以及客户端角色等,具体说明如下:
1.抽象享元角色(Flyweight):此角色是所有的具体享元类的超类,为这些类规定出需要实现的公共接口或抽象类。那些需要外蕴状态的操作可以通过方法的参数传入。抽象享元的接口使得享元变得可能,但是并不强制子类实行共享,因此并非所有的享元对象都是可以共享的。
2.具体享元角色(ConcreteFlyweight):实现抽象享元角色所规定的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。享元对象的内蕴状态必须与对象所处的周围环境无关,从而使得享元对象可以在系统内共享。有时候具体享元角色又称为单纯具体享元角色,因为复合享元角色是有单纯具体享元角色通过复合而成的。
3.复合享元角色(UnsharableFlyweight):复合享元角色所代表的对象是不可以共享的,但是一个复合享元对象可以分解成为多个本身是单纯享元对象的组合。复合享元角色又称为不可共享的享元对象。这个角色一般很少使用。
4.享元工厂(FlyweightFactory)角色:负责创建和管理享元角色。本角色必须保证享元对象可以被系统适当的共享。当一个客户端对象请求一个享元对象的时候,享元工厂角色需要检查系统中是否已经有一个复合要求的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个新的合适的享元对象。
5.客户端角色:本角色还需要自行存储所有享元对象的外蕴状态。
网友评论