1、一个原则
类应该对扩展开放,对修改关闭
2、定义装饰者模式
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
1. Component就是装饰器模式中公共方法的类,在装饰器模式结构图的顶层。
2. ConcreateComponent是转换器模式中具体的被装饰的类,IO包中的媒体流就是此种对象。
3. Decorator装饰器模式中的核心对象,所有具体装饰器对象的父类,完成装饰器的部分职能。在上面的例子中Decorator类和这里的对应。该类可以只做一些简单的包裹被装饰的对象,也可以还包含对Component中方法的实现……他有一个鲜明的特点:继承至Component,同时包含一个Component作为其成员变量。装饰器模式动机中的动态地增加功能是在这里实现的。
4. ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装饰器对象,他们完成具体的装饰功能。装饰功能的实现是通过调用被装饰对象对应的方法,加上装饰对象自身的方法。这是装饰器模式动机中的添加额外功能的关键。
从上面图中你可能还会发现:ConcreteDecoratorA和ConcreteDecoratorB的方法不一样,这就是一般设计模式中谈及装饰器模式的“透明装饰器”和“不透明装饰器”。“透明装饰器”就是整个Decorator的结构中所有的类都保持同样的“接口”(这里是共同方法的意思),这是一种极其理想的状况,就像餐饮的例子一样。现实中绝大多数装饰器都是“不透明装饰器”,他们的“接口”在某些子类中得到增强,主要看这个类与顶层的抽象类或者接口是否有同样的公共方法。IO中的ByteArrayInputStream就比Inputstrem抽象类多一些方法,因此IO中的装饰器是一个“不通明装饰器”。下面是IO中输入字节流部分的装饰器的结构图。
- #ifndef DECORATOR_H
- #define DECORATOR_H
- // 抽象基类,定义一个对象接口,可以为这个接口动态的添加职责.
- class Component
- {
- public:
- Component(){}
- virtual ~Component(){}
- // 纯虚函数,由派生类实现
- virtual void Operation() = 0;
- };
- // 抽象基类,维护一个指向Component对象的指针
- class Decorator: public Component
- {
- public:
- Decorator(Component* pComponent) : m_pComponent(pComponent){}
- virtual ~Decorator();
- protected:
- Component* m_pComponent;
- };
- // 派生自Component,在这里表示需要给它动态添加职责的类
- class ConcreateComponent
- : public Component
- {
- public:
- ConcreateComponent(){}
- virtual ~ConcreateComponent(){}
- virtual void Operation();
- };
- // 派生自Decorator,这里代表为ConcreateComponent动态添加职责的类
- class ConcreateDecorator
- : public Decorator
- {
- public:
- ConcreateDecorator(Component* pComponent) : Decorator(pComponent){}
- virtual ~ConcreateDecorator(){}
- virtual void Operation();
- private:
- void AddedBehavior();
- };
- #endif
- #include "Decorate.h"
- #include <iostream>
- Decorator::~Decorator()
- {
- delete m_pComponent;
- m_pComponent = NULL;
- }
- void ConcreateComponent::Operation()
- {
- std::cout << "Operation of ConcreateComponentn";
- }
- void ConcreateDecorator::Operation()
- {
- m_pComponent->Operation();
- std::cout<<" ";
- AddedBehavior();
- }
- void ConcreateDecorator::AddedBehavior()
- {
- std::cout << "AddedBehavior of ConcreateDecoratorn";
- }
- #include "Decorate.h"
- #include <stdlib.h>
- int main()
- {
- // 初始化一个Component对象
- Component* pComponent = new ConcreateComponent();
- // 采用这个Component对象去初始化一个Decorator对象,
- // 这样就可以为这个Component对象动态添加职责
- Decorator* pDecorator = new ConcreateDecorator(pComponent);
- pDecorator->Operation();
- delete pDecorator;
- system("pause");
- return 0;
- }
1. InputStream是装饰器的顶层类,一个抽象类!包括一些共有的方法,如:1.读方法――read(3个);2.关闭流的方法――close;3.mark相关的方法――mark、reset和markSupport;4.跳跃方法――skip;5.查询是否还有元素方法――available。图中红色的表示。
2. FileInputStream、PipedInputStream…五个紫色的,是具体的被装饰对象。从他们的“接口”中可以看出他们一般都有额外的方法。
3. FilterInputStream是装饰器中的核心,Decorator对象,图中蓝色的部分。
4. DataInputStream、BufferedInputStream…四个是具体的装饰器,他们保持了和InputStream同样的接口。
5. ObjectInputStream是IO字节输入流中特殊的装饰器,他不是FilterInputStream的子类(不知道Sun处于何种意图不作为FileterInputStream的子类,其中流中也有不少的例子)。他和其他FilterInputStream的子类功能相似都可以装饰其他对象。
IO包中不仅输入字节流是采用装饰器模式、输出字节流、输入字符流和输出字符流都是采用装饰器模式。关于IO中装饰器模式的实现可以通过下面的源代码分析从而了解细节。
我觉得这个模式的精髓和composite模式其实是一样的,
那就是把一系列的具有相似的类设计成具有统一接口。
对于decorate,用户可以用这个统一的接口来操作任何一个类。这样就可以用这些类相互修饰。产生复杂的对象。而用户接口不变。
对于composite,用户也是可以用这个统一的接口来操作,这里和decorate的区别是,decorate是用一个修饰另一个,以此类推,可以递归修饰。而composite则是可以一个包含多个,并且可以递归包含。
这两个模式的精髓都在于统一接口,这样就可以使用递归来实现复杂对象,这两个模式其实是形似而神非,因为它们是针对两个完全不的问题的解决方案。组合模式用于使用已有对象来组成一个复杂的对象,而修饰模式重用已有对象的行为并进行一些改变或扩展。组合模式关心的是数据的组织,而修饰模式关心的则是对行为的重用和改变。整饰模式所解决的问题与修略模式所解决的问题有些相似并且有交集,有些问题可以选择用修饰模式或是用策略模式,而组合模式对这些问题是无能为力的。
其实修饰模式和策略模式的思想关键就是:使用组合而不是继承来重用代码。它们所解决的问题通常会有通过继承解决的途径,只是随着对象规模的增长会变得很复杂,并且不够灵活。