频道栏目
首页 > 资讯 > 其他综合 > 正文

GOF设计模笔记式之结构模型

16-04-20        来源:[db:作者]  
收藏   我要投稿

1 前言

上一篇我们研究了创建型模式,这一篇们开始研究结构模型,这里主要解决合成还是继承的问题。如何通过适当的方法给类解耦。这里是我们主要考虑的问题,这里6种设计模式的关系我就先不研究,了解每一种模式再说。

2 模式特点

这里主要介绍六中设计模式的特点与结构,记录下自己的想法。

2.1 ADAPTER(适配器) — 类对象结构型模式

2.1.1. 意图

将一个类的接口转换成客户希望的另外一个接口。 A d a p t e r模式使得原本由于接口不兼容
而不能一起工作的那些类可以一起工作。

2.1.2 适用性

以下情况使用Adapter模式

你想使用一个已经存在的类,而它的接口不符合你的需求。你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。(仅适用于对象Adapter)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。

2.1.3 结构图

结构如

2.1.4 效果

类适配器和对象适配器有不同的权衡。类适配器

用一个具体的Adapter类对Adapter和Target进行匹配。结果是当我们想要匹配一个类以及所有它的子类时,类Adapter不能胜任工作。使得Adapter可以重定义Adaptee的部分行为,因为Adapter是Adaptee的一个子类。仅仅引入了一个对象,并不需要额外的指针以间接得到 Adaptee。对象适配器则允许一个Adapter与多个Adaptee — 即Adaptee本身以及它的所有子类 (如果有子类的话)—同时工作。Adapter也可以一次给所有的Adaptee添加功能。使得重定义Adaptee的行为比较困难。这就需要生成 Adapte e的子类并且使得Adapter引用
这个子类而不是引用Adaptee本身。

2.1.5 注意

这里面比价复杂,适配器模式主要是转换数据格式的。也就是接口,listview中的adapter就是adapter模式

2.2 BRIDGE(桥接) — 对象结构型模式

2.2.1 意图

将抽象部分与它的实现部分分离,使它们都可以独立地变化。

2.2.2 适用性

以下一些情况使用Bridge模式:

你不希望在抽象和它的实现部分之间有一个固定的绑定关系。 例如这种情况可能是因为,在程序运行时刻实现部分应可以被选择或者切换。类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这时 Bridge模式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。(C++)你想对客户完全隐藏抽象的实现部分。在 C++中,类的表示在类接口中是可见的。有许多类要生成。这样一种类层次结构说明你必须将一个对象分解成两个部分。 R u m b a u g h称这种类层次结构为“嵌套的普化”(nested generalizations) 。你想在多个对象间共享实现(可能使用引用计数) ,但同时要求客户并不知道这一点。

2.2.3 结构图

这里写图片描述

2.2.4 效果

Bridge模式有以下一些优点:

分离接口及其实现部分 一个实现未必不变地绑定在一个接口上。抽象类的实现可以在运行时刻进行配置,一个对象甚至可以在运行时刻改变它的实现。将Abstraction与Implementor分离有助于降低对实现部分编译时刻的依赖性,当改变一个实现类时,并不需要重新编译Abstraction类和它的客户程序。为了保证一个类库的不同版本之间的二进制兼容性,一定要有这个性质。另外,接口与实现分离有助于分层,从而产生更好的结构化系统,系统的高层部分仅需知道Abstraction和Implementor即可。提高可扩充性 你可以独立地对Abstraction和Implementor层次结构进行扩充。

2.2.5 注意

有助于解耦

2.3 COMPOSITE(组合) — 对象结构型模式

2.3.1 1. 意图

将对象组合成树形结构以表示“部分 -整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。

2.3.2 适用性

你想表示对象的部分-整体层次结构。你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

2.3.3结构图

这里写图片描述

2.3.4效果

定义了包含基本对象和组合对象的类层次结构 基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断的递归下去。客户代码中,任何用到基本对象的地方都可以使用组合对象。简化客户代码 客户可以一致地使用组合结构和单个对象。通常用户不知道 (也不关心)处理的是一个叶节点还是一个组合组件。这就简化了客户代码 , 因为在定义组合的那些类中不需要写一些充斥着选择语句的函数。使得更容易增加新类型的组件 新定义的Composite或Leaf子类自动地与已有的结构和客户代码一起工作,客户程序不需因新的Composite类而改变。使你的设计变得更加一般化 容易增加新组件也会产生一些问题,那就是很难限制组合中的组件。有时你希望一个组合只能有某些特定的组件。使用Composite时,你不能依赖类型系统施加这些约束,而必须在运行时刻进行检查。

2.3.5 注意

这里最好的例子是view类其实就是一个递归调用。来解析特定的内容。有利于解耦。并且对于自己不知道内容的编程非常重要

2.4 DECORATOR(装饰) — 对象结构型模式

2.4.1 意图

动态地给一个对象添加一些额外的职责。就增加功能来说, dectortor模式相比生成子类更为灵活。

2.4.2 适用性

在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。处理那些可以撤消的职责。当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

2.4.3结构图

这里写图片描述

2.4.4 效果

Decorator模式至少有两个主要优点和两个缺点:

比静态继承更灵活 与对象的静态继承(多重继承)相比, Decorator模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和删除职责。相比之下,继承机制会产生许多新的类,并且会增加系统的复杂度。此外,为一个特定的Compoent类提供多个不同的Decorator类,这就使得你可以对一些职责进行混合和匹配。使用Decorator模式可以很容易地重复添加一个特性。避免在层次结构高层的类有太多的特征Decorator模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征,相反,你可以定义一个简单的类,并且用Decorator类给它逐渐地添加功能。可以从简单的部件组合出复杂的功能。这样,应用程序不必为不需要的特征付出代价。同时也更易于不依赖于Decorator所扩展(甚至是不可预知的扩展)的类而独立地定义新类型的Decorator。扩展一个复杂类的时候,很可能会暴露与添加的职责无关的细节。 Decorator与它的Compoent不一样 Dectorator是一个透明的包装。如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此,使用装饰时不应该依赖对象标识。有许多小对象 采用Dectorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。

2.4.5 注意

这种设计模式感觉平时不太常用。

2.5 FACADE(外观) — 对象结构型模式

2.5.1 意图

为子系统中的一组接口提供一个一致的界面, F a c a d e模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

2.5.2 适用性

在遇到以下情况使用Facade模式

当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过Facade层。客户程序与抽象类的实现部分之间存在着很大的依赖性。引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。当你需要构建一个层次结构的子系统时,使用Facadee模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过Facade进行通讯,从而简化了它们之间的依赖关系。

2.5.3 结构图

这里写图片描述

2.5.4 效果

Facade模式有下面一些优点:

它对客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。松耦合关系使得子系统的组件变化不会影响到它的客户。Facade模式有助于建立层次结构系统,也有助于对对象之间的依赖关系分层。Facade模式可以消除复杂的循环依赖关系。这一点在客户程序与子系统是分别实现的时候尤为重要。在大型软件系统中降低编译依赖性至关重要。在子系统类改变时,希望尽量减少重编译工作以节省时间。用Facade可以降低编译依赖性,限制重要系统中较小的变化所需的重编译工作Facade模式同样也有利于简化系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。如果应用需要,它并不限制它们使用子系统类。因此你可以在系统易用性和通用性之间加以选择。

2.5.5 注意

一切目的是为了封装。功能封装,组件解耦。

2.6 FLYWEIGHT(享元) — 对象结构型模式

2.6.1 意图

运用共享技术有效地支持大量细粒度的对象。

2.6.2 适用性

Flyweight模式的有效性很大程度上取决于如何使用它以及在何处使用它。当以下情况都成立时使用Flyweight模式:

一个应用程序使用了大量的对象。完全由于使用大量的对象,造成很大的存储开销。对象的大多数状态都可变为外部状态。如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。

2.6.3 结构图

这里写图片描述

2.6.4 效果

使用Flyweight模式时,传输、查找和 /或计算外部状态都会产生运行时的开销,尤其当Flyweight原先被存储为内部状态时。然而,空间上的节省抵消了这些开销。共享的Flyweight越多,空间节省也就越大。
存储节约由以下几个因素决定:
? 因为共享,实例总数减少的数目
? 对象内部状态的平均数目
? 外部状态是计算的还是存储的

2.6.4 注意

我不是很明白。在当前我考虑不到大量的类对象的创建。

2.7 PROXY(代理) — 对象结构型模式

2.7.1 意图

为其他对象提供一种代理以控制对这个对象的访问。

2.7.2 适用性

在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用Proxy模式。下面是一些可以使用Proxy模式常见情况:

远 程 代 理 ( Remote Proxy) 为 一 个 对 象在 不 同 的 地 址 空间 提 供 局 部 代 表。虚代理(Virtual Proxy)根据需要创建开销很大的对象。保护代理(Protection Proxy)控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。

2.7.3 结构图

这里写图片描述

2.7.4 效果

Proxy模式在访问对象时引入了一定程度的间接性。根据代理的类型,附加的间接性有多种用途:

Remote Proxy可以隐藏一个对象存在于不同地址空间的事实。 Virtual Proxy 可以进行最优化,例如根据要求创建对象。 Protection Proxies和Smart Reference都允许在访问一个对象时有一些附加的内务处理(Housekeeping task) 。

2.7.5 注意

这是个很有用的模式,

分析

相关TAG标签
上一篇:【hdu 5510】【2015ACM/ICPC亚洲区沈阳站-重现赛 】Bazinga题意&题解&代码(C++)
下一篇:Java ArrayList实现原理
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站