设计模式——结构型模式

1.代理模式※

(1)代理模式的定义

       代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

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

远程代理(Remote Proxy)可以隐藏一个对象存在于不同地址空间的事实。

虚代理(Virtual Proxy)可以进行最优化,例如根据要求创建对象。

保护代理(Protection Proxies)和智能引用(Smart Reference)都允许在访问一个对象时有一些附加的内务处理。

 

(2)为什么要用代理模式

       中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。

       开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。

 

3)优缺点

A.优点

       代理模式能够协调调用者和被调用者吗,在一定程度上降低了系统的耦合度。

       远程代理是的客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。

       虚拟代理通过使用一个小对象来代表一个大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度。

      保护代理可以控制对真实对象的使用权限。

B. 缺点

       由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。

       实现代理模式需要额外的工作,有些代理秘书的实现比较复杂。

 

(4) 适用性

下面是一些可以使用Proxy模式常见的情况:

远程代理(Remote Proxy) 为一个对象在不同的地址空间提供局部代表。

虚代理(Virual Proxy) 根据需要创建开销很大的对象。

保护代理(Protection Proxy) 控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。

智能指引(Smart Reference) 取代了简单的指针,它在访问对象时执行一些附加操作。典型用途包括:

对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放它。

当第一次引用一个持久对象时,将它装入内存。

在访问一个实际对象前,检查是否已经锁定了它,以确保其他对象不能改变它。

 

(5)与适配器模式的区别

       适配器模式是由于原接口与目标接口不兼容而产生的。代理模式则拥有与被代理者相同的接口,但是其具有自己独有的职责,将使用与被代理者的实现隔离开来。

(6)动态代理

       Java使用JDK实现动态代理类技术核心为Proxy类和一个InvocationHandler 接口。

 

2.装饰模式※

(1)概念

       时常会遇到这样一种情况,我已经设计好了一个接口,并且也有几个实现类,但是这时我发现我设计的时候疏忽了,忘记了一些功能,或者后来需求变动要求加入一些功能,最简单的做法就是修改接口,添加函数,然后继承类中都相应的添加实现,这样做倒也没什么问题,但是如果这种变化来个好几次或者继承类非常多,那工作量可就大了。

       所以大神们想出了装饰模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。

                            

 

用法:

int main()  

{    

Component* pComponent = new ConcreteComponent();      

ConcreteDecorator* pConDecorator = new ConcreteDecorator();       pConDecorator->setComponent(pComponent);    

  pConDecorator->operation();    

pConDecorator->addBehavior();    

 return 0;

}

 

2优缺点

A.优点

       比静态继承更灵活 与对象的静态继承(多重继承)相比,Decorator模式提供了更加灵活的向对象添加职责的方式。可以用添加和分离的方法,用装饰在运行时刻增加和删除职责。相比之下,继承机制要求为每个添加的职责创建一个新的子类。这会产生许多新的类,并且会增加系统的复杂度。此外,为一个特定的Component类提供多个不同的Decorator类,这就使得你可以对一些职责进行混合和匹配。

       避免在层次结构高层的类有太多的特征 Decorator模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可预见的特征,相反,你可以定义一个简单的类,并用Decorator类给它逐渐地添加功能。可以从简单的部件组合出复杂的功能。

B.缺点

       Decorator与它的Component不一样 Decorator是一个透明的包装。如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有差别的,因此,使用装饰时不应该依赖对象标识。

       有许多小对象 采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象。这些对象仅仅在他们相互连接的方式上有所不同,而不是它们的类或是它们的属性值有所不同。尽管对于那些了解这些系统的人来说,很容易对它们进行定制,但是很难学习这些系统,排错也很困难。

 

3适用性

  以下情况使用Decorator模式:

       在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。 

       当不能采用生成子类的方法进行扩充时。一种情况是,可以有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

 

3.适配器模式

       将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作。——《设计模式:可复用面向对象软件的基础》

1类适配器模式(class adapter pattern)

 

2对象适配器模式(object adapter pattern)

 

3)缺省适配器模式(default adapter pattern),也叫默认适配器模式、接口适配器模式

 

(4)缺点过多地使用适配器,增加系统理解难度。

 

(5)和代理模式的区别

       适配器模式是由于原接口与目标接口不兼容而产生的。代理模式则拥有与被代理者相同的接口,但是其具有自己独有的职责,将使用与被代理者的实现隔离开来。

 

4.外观模式

       外观模式通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。该模式对外有一个统一接口,外部应用程序不用关心内部子系统的具体的细节,这样会大大降低应用程序的复杂度,提高了程序的可维护性。

 

 

5.桥接模式

(1)模式来源

       设想如果要绘制矩形、圆形、椭圆、正方形,我们至少需要4个形状类,但是如果绘制的图形需要具有不同的颜色,如红色、绿色、蓝色等,此时至少有如下两种设计方案:

        • 第一种设计方案是为每一种形状都提供一套各种颜色的版本。

 

        • 第二种设计方案是根据实际需要对形状和颜色进行组合。

 

       对于有两个变化维度(即两个变化的原因)的系统,采用方案二来进行设计系统中类的个数更少,且系统扩展更为方便。设计方案二即是桥接模式的应用。

 

2模式结构

 

实例a:

 

这就将pen和color分离开来,各自发展。

实例b,跨平台播放器:

 

 

6.组合模式

(1)定义:将对象组合成树形结构以表示“部分-整体”的层次结构,使客户端对单个对象和组合对象保持一致的方式处理。所以,合成模式必须在合适的地方提供子对象的管理方法,诸如:add()、remove()、以及getChild()等。透明式的合成模式要求所有的具体构件类,不论树枝构件还是树叶构件,均符合一个固定接口,如下。

 

(2)示例:文件系统就是典型的组合模式,如下图是window系统D盘符下的部分目录组织结构,红橙色的是目录,浅绿色的是文件,这里目录和文件是可以看成是同一种对象对待。

 

 

7.享元模式

(1)定义:运用共享技术有效地支持大量细粒度的对象。

 

(2)示例

       String常量池、数据库连接池、缓冲池等等都是享元模式的应用,所以说享元模式是池技术的重要实现方式。

  比如我们每次创建字符串对象时,都需要创建一个新的字符串对象的话,内存开销会很大,所以如果第一次创建了字符串对象“adam“,下次再创建相同的字符串”adam“时,只是把它的引用指向”adam“,这样就实现了”adam“字符串再内存中的共享。

方法就是用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象,用HashMap/HashTable存储。

 

参考:

https://www.cnblogs.com/daniels/p/8242592.html

https://blog.csdn.net/huangjh2017/article/details/78595072

https://www.cnblogs.com/cxjchen/p/3161686.html

https://blog.csdn.net/huangjh2017/article/details/78524418

https://www.cnblogs.com/mingmingcome/p/9810731.html

https://www.cnblogs.com/alsf/p/8506912.html

https://www.jianshu.com/p/6c721472be83

https://blog.csdn.net/huangjh2017/article/details/78472975

https://blog.csdn.net/u014727260/article/details/82722473

https://www.cnblogs.com/adamjwh/p/9070107.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章