1.适配器模式(Adapter)
看了<<设计模式>>和这篇文章,觉得适配器的一个重点就是 对象所提供的接口并不一定能适应我们的新环境,我们就要对其转换成我们需要的接口(其实不适应新环境就是类成员函数名称不一样,无法通过父类指针直接操作子类)
设计模式里面有一个例子就是在程序上绘制几何图形的问题,我们有LineShape,PolygnShape都继承自Shape,也有统一的接口,比如有个接口BoundingBox,现在我们要加入一个TextShape,一般是要自己重新写一个,但是已经有程序库提供了TextView经过稍微更改可以满足我们的需求,但是类的成员函数名跟我们不一致,比如TextView有一个成员函数BoundingFun的功能跟BoundingBox一样
这种情况下我一般可以直接使用TextView或者创造一个类TextView2,继承自TextView,这个也是我认为比较好的方法,节省时间,又重用代码
但是如果我们想可以直接通过shape的指针来操作这个TextShape,也就是说我们的客户只要new了一个几何图形后,不管是LineShape还是TextShape,都可以通过一样的接口去操作,这个时候我们可以让TextShape 以public的方式继承Shape,以private的方式继承TextView,或者有个私有的TextView成员变量,这样我们就可以达到上述的目的
适配器模式又分为对象适配器和类适配器,其实就是一个通过组合,一个通过继承来实现适配器,当然我更倾向于组合,因为如果我们后面TextView有了子类,比如TextView2,当我们要对这些类进行适配,如果使用继承我们就需要再创造一个类,比如TextShape2,但是如果我们使用组合,我们就可以通过给TextShape来增加一个SetTextView的接口,可以直接通过同样的接口来操作TextView2
装饰者模式(DECORATOR):
顾名思义,装饰者模式就是给类加上一点装饰,我们有一个DECORATOR和Component,如果我们要对Component或者他的基类进行附加操作,那么我们可以用DECORATOR对Component进行装饰,然后DECORATOR对Component的操作进行附加操作,DECORTOR更倾向于改变对象的外壳,而不是Strategy倾向于改变对象的内核
<<设计模式>>里面有一个例子,就是TextView控件的问题,TextView控件有一个父类VisualComponent,TextView通过Draw来绘制,但是不支持有滚动条,现在我们需要TextView有滚动条的功能,那我们该怎么办??
一般我会新建一个类,名字叫TextViewScroll,然后有这样如果我需要一个有滚动条的TextView控件,那么只要新建这个类就可以了,但是如果我们现在有另外一个控件,比如List,这个类也是继承自VisualComponent,这个控件也需要滚动条,那我们是不是还要再创建一个TextViewScroll??
这个时候我们 就需要一个装饰者,就是给TextView和List装饰一个滚动条,这个时候我们也有一个装饰者Decorator,这个类继承自VisualComponent,而且这个类可以接受一个VisualComponent的类或者子类,当我们需要滚动条的时候,只要让Decorator去装饰传入的VisualComponent的类,在Draw控件的时候顺便Draw滚动条
这个模式有个缺点就是如果被装饰的对象没有公共的父类,并且没有统一的接口,那么就没办法使用装饰者,只能用我说的那个方法(可能后面有其他的方法,再继续看看)
享元模式(Flyweight)
享元模式给我的感觉更像是另外一个版本的写时复制,不同的是更改的时候,比如有三个字符串A,B,C,A字符串指向"ABC",B指向"BCD",此时如果C=A,那么C也指向"ABC",内存中实际只有两个字符串"ABC"和"BCD",如果这个时候把C="BCD",如果是写时复制,那么这个时候C会指向"BCD",但是不是B所指向的"BCD",是新的内存,这样内存中就有三块内存,ABC,BCD,BCD,如果是享元模式,那么C会先在所有可以共享的字符串里面查找是否有"BCD",如果有,那么直接把C指向"BCD",那样内存中就只有两块,"ABC"和"BCD"
我的理解就是享元会创造一组可以共享的内存,如果我们需要更改一些对象的数据,那么会先在这些内存中查找,然后直接让该对象指向共享的内存,没有再进行创建
享元适用于一些有大量重复内容的数据,比如<<设计模式>>提到的一个文档编辑器,文档编辑器如果每一个字符都要用一个对象存储的话,那么对内存是很损耗的,但实际上字母也就二十几个而已,这些字母都是一样的,只有字符的位置和颜色不一样,这个时候字符就是 可以共享的,只有位置和颜色不可共享,可以把可共享的提取出来(当然一个字符指针实际上比一个字母更耗内存,这里只是举个例子)
外观和代理(FACADE,PROXY)
说实话我觉得这两个模式是一样的,就是再加一层用以掩盖内部的情况,不过我没想到share_ptr是代理模式
桥接模式(BRIDGE):
桥接模式给我的感觉也是一个代理模式或者说是外观模式的变种,他们提供给用户的都只是接口,掩盖了内部的实现
<<设计模式>>举了个例子,就是跨平台的窗口,BRIDGE模式将抽象和实现分离,实现就是WindowImp这些,通过Windows类里面的WindowsImp指针,根据不同的平台创建不同的类,然后就可以掩盖Window究竟调用的是XWindow还是PMWindow的实现,
组合模式(COMPOSITE):
如上图,组合模式就是用户对单个对象还是组合对象的使用都具有一致性,我的理解就是不管是0403这个节点也好,还是04-0401-0402-0403,还是整棵树,对于用户提供的接口都是一样的,用户不必去关心Add或者Remove的时候究竟是叶节点还是子树
看设计模式感觉看得还是挺迷糊的,只能说慢慢去理解,不过设计模式这种东西毕竟还是靠实践,只能说以后做东西尽量看看能不能使用设计模式,当然只是为了增加经验而已,千万不要动不动就设计模式设计模式
看完了这些,感觉结构型模式还是要在知道要做什么基础上去使用,否则根本无法把整个架构给设计好,不过目前我还没到那个水平,只能说尽量把代码写得低耦合,以及可读性好,这样后期更改会很容易