最近看到《设计之禅》的装饰器模式,特用C++实现了一遍,发现有些有意思的东西需要探究一下。
UML类图:
一. C++实现
#include <stdio.h>
/// Base
class Component
{
public:
virtual ~Component(){}
virtual int operate() = 0;
};
/// ConcreteComponent
class ConcreteComponent: public Component
{
public:
ConcreteComponent()
{
}
virtual ~ConcreteComponent()
{
printf("ConcreteComponent Destroy %#04x\n", this);
}
int operate()
{
printf("ConcreteComponent operate\n");
return 0;
}
};
/// Decorator
class Decorator: public Component
{
public:
virtual ~Decorator()
{
printf("Decorator destroy:%#04x base:%#04x\n", this, m_component);
delete m_component;
m_component = NULL;
}
protected:
Component* m_component;
};
/// ConcreteDecoratorA
class ConcreteDecoratorA: public Decorator
{
public:
explicit ConcreteDecoratorA(Component *ins)
{
m_component = ins;
}
~ConcreteDecoratorA()
{
printf("ConcreteDecoratorA destroy:%#04x\n", this);
}
int operate()
{
int ret = m_component->operate();
printf("ConcreteDecoratorA operate\n");
return ret;
}
};
/// ConcreteDecoratorB
class ConcreteDecoratorB: public Decorator
{
public:
explicit ConcreteDecoratorB(Component *ins)
{
m_component = ins;
}
~ConcreteDecoratorB()
{
printf("ConcreteDecoratorB destroy:%#04x\n", this);
}
int operate()
{
int ret = m_component->operate();
printf("ConcreteDecoratorB operate\n");
return ret;
}
};
// 检测指针是否释放
Component *p = NULL, *q = NULL, *h = NULL;
/**
* main
*/
int main(int argc, char **argv)
{
Component *component = new ConcreteComponent(); p = component;
component = new ConcreteDecoratorA(component); q = component;
component = new ConcreteDecoratorB(component); h = component;
component->operate();
printf("Concrete:%#04x Concrete1:%#04x Concrete2:%#04x\n\n", p, q, h);
// 内存是否泄露?
delete component;
component = NULL;
return 0;
}
装饰器模式提供比继承更有弹性的扩展方案,缺点产生了大量包装类,业务逻辑比较复杂。
上图实现是调用了三次new,却只delete一次,是否会发生内存泄露?
先看结果:
ConcreteComponent operate ConcreteDecoratorA operate ConcreteDecoratorB operate Concrete:0x21d9010 Concrete1:0x21d9030 Concrete2:0x21d9050 ConcreteDecoratorB destroy:0x21d9050 Decorator destroy:0x21d9050 base:0x21d9030 ConcreteDecoratorA destroy:0x21d9030 Decorator destroy:0x21d9030 base:0x21d9010 ConcreteComponent Destroy 0x21d9010
分析:在析构ConcreteDecoratorB后,会再析构父类Decorator,但此次的Decorator已被构造函数替换成ConcreteDecoratorA,则析构ConcreteDecoratorA,同理再析构ConcreteComponent。通过Componenet成员变量达到析构了所有堆变量,实在是高!
二. java IO
Java IO提供很多实用的工具类,各种read(), readLine() 调用,典型的装饰器模式。
FileInputStream fis = new FileInputStream("~/test.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(b, off, len);
源码跟踪:
BufferedInputStream::read(b, off, len);
getInIfOpen().read(b, off, len);
InputStream::read(b, off, len);
BufferedInputStream利用缓冲输入改善行为,底层调用FileInputStream的read(),而FileInputStream调用InputStream的read()。