在设计的过程中,经常会遇到IS-A和HAS-A的问题,相应的UML图也就有很大的区别,一个是继承,一个是组合。
这样的问题很难给出明确的答案,只能是根据实际的需求,结合项目规模来确定最后的设计原则。
当你发觉使用继承来扩展对象的功能会带来一些问题,例如:
1)扩展缺乏灵活性
2)子类膨胀
这个时候,你可以考虑使用组合的办法,而Decorator是一种很有效的组合模式。
类继承是静态扩展,而Decorator则是动态扩展。
先看一下GOF里面给出的类图:
可以看出来,需要装饰的对象(ConcreateComponent)和装饰器(Decorator)继承自同一个接口(Component),
这样做是为了保持接口的一致性。
具体的Sample例子就不给出了,看一下Decorator在类库的设计里面的是如何体现的。
Java和.Net里面的IO都是很好的Decorator的范例,我就重点介绍一下.Net里面的IO,Java的IO也是类似的。
MemoryStream、FileStream、NetworkStream是需要被装饰的对象,
BufferedStream、CryptoStream则是装饰器。
GOF给出的类图中,在只有一个装饰器的时候,Decorator类这一层是不必须的,但是为了扩展需要,一般来说,在设计的时候还是需要考虑到的。
Decorator在形式上是IS-A的继承关系,但在运行中表现得是HAS-A的组合关系,这个是在设计时尤其应该注意的地方。