- 繼承屬於擴充形式之一,但不見得是達到彈性設計的最佳方式。
- 在我們的設計中,應該允許行為可以被擴充,而無須修改計有的程式碼。
- 合成與委派可時常在執行時期,動態的加上新的行為。
- 除了繼承,裝飾者模式也可以讓我們擴充行為。
#include <stdlib.h>
#include <stdio.h>
class CComponent
{
public:
CComponent()
{
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual ~CComponent()
{
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual int value(void) = 0;
};
class CConcreteComponent : public CComponent
{
private:
int val;
public:
CConcreteComponent()
{
val = 10;
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual ~CConcreteComponent()
{
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual int value(void)
{
printf("%s\n", __PRETTY_FUNCTION__);
return val;
}
};
class CDecorator : public CComponent
{
public:
CDecorator()
{
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual ~CDecorator()
{
printf("%s\n", __PRETTY_FUNCTION__);
}
// 加上新的行為
virtual void method(void) = 0;
};
class CConcreteDecoratorA : public CDecorator
{
private:
CComponent *component;
public:
CConcreteDecoratorA(CComponent *c) : component(c)
{
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual ~CConcreteDecoratorA()
{
printf("%s\n", __PRETTY_FUNCTION__);
delete component;
}
virtual void method(void)
{
}
// 將原生物件因裝飾後加入新的行為
virtual int value(void)
{
printf("%s\n", __PRETTY_FUNCTION__);
return 20 + component->value();
}
};
class CConcreteDecoratorB : public CDecorator
{
private:
CComponent *component;
public:
CConcreteDecoratorB(CComponent *c) : component(c)
{
printf("%s\n", __PRETTY_FUNCTION__);
}
virtual ~CConcreteDecoratorB()
{
printf("%s\n", __PRETTY_FUNCTION__);
delete component;
}
virtual void method(void)
{
}
// 將原生物件因裝飾後加入新的行為
virtual int value(void)
{
printf("%s\n", __PRETTY_FUNCTION__);
return 30 + component->value();
}
};
int main()
{
CComponent *component = new CConcreteComponent();
printf("\n");
component = new CConcreteDecoratorA(component);
printf("\n");
component = new CConcreteDecoratorB(component);
printf("===============================================\n");
printf("%d\n", component->value());
printf("===============================================\n");
delete component;
}
執行結果
CComponent::CComponent()
CConcreteComponent::CConcreteComponent()
CComponent::CComponent()
CDecorator::CDecorator()
CConcreteDecoratorA::CConcreteDecoratorA(CComponent*)
CComponent::CComponent()
CDecorator::CDecorator()
CConcreteDecoratorB::CConcreteDecoratorB(CComponent*)
===============================================
virtual int CConcreteDecoratorB::value()
virtual int CConcreteDecoratorA::value()
virtual int CConcreteComponent::value()
60
===============================================
virtual CConcreteDecoratorB::~CConcreteDecoratorB()
virtual CConcreteDecoratorA::~CConcreteDecoratorA()
virtual CConcreteComponent::~CConcreteComponent()
virtual CComponent::~CComponent()
virtual CDecorator::~CDecorator()
virtual CComponent::~CComponent()
virtual CDecorator::~CDecorator()
virtual CComponent::~CComponent()
在此要思考裝飾者的結構式裡用 delete 是否恰當,原程式是在 Java 上時做,但 C++ 不具備有 garbage collection 的功能。若不再解構式中釋放則會產生 memory leak 的問題。但在另一個 case 裡則會引發錯誤。
使用時機須在思考
int main()
{
CComponent *component;
CConcreteComponent concreteComponent;
printf("\n");
component = new CConcreteDecoratorA(&concreteComponent);
printf("\n");
component = new CConcreteDecoratorB(component);
printf("===============================================\n");
printf("%d\n", component->value());
printf("===============================================\n");
delete component;
}
CComponent::CComponent()
CConcreteComponent::CConcreteComponent()
CComponent::CComponent()
CDecorator::CDecorator()
CConcreteDecoratorA::CConcreteDecoratorA(CComponent*)
CComponent::CComponent()
CDecorator::CDecorator()
CConcreteDecoratorB::CConcreteDecoratorB(CComponent*)
===============================================
virtual int CConcreteDecoratorB::value()
virtual int CConcreteDecoratorA::value()
virtual int CConcreteComponent::value()
60
===============================================
(執行 delete)
virtual CConcreteDecoratorB::~CConcreteDecoratorB()
virtual CConcreteDecoratorA::~CConcreteDecoratorA()
virtual CConcreteComponent::~CConcreteComponent()
virtual CComponent::~CComponent()
*** Error in `./decorator': double free or corruption (out): 0xbfa397c8 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x767e2)[0xb74ee7e2]
/lib/i386-linux-gnu/libc.so.6(+0x77530)[0xb74ef530]
/usr/lib/i386-linux-gnu/libstdc++.so.6(_ZdlPv+0x1f)[0xb7691b4f]
./decorator[0x8048980]
./decorator[0x8048aec]
./decorator[0x8048b3f]
./decorator[0x8048c10]
./decorator[0x8048c63]
./decorator[0x80487f6]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0xb7491935]
./decorator[0x8048651]
======= Memory map: ========
08048000-0804a000 r-xp 00000000 08:01 393246 /home/archer/src/HeadFirstDesignPatterns/chap03/decorator
0804a000-0804b000 r--p 00001000 08:01 393246 /home/archer/src/HeadFirstDesignPatterns/chap03/decorator
0804b000-0804c000 rw-p 00002000 08:01 393246 /home/archer/src/HeadFirstDesignPatterns/chap03/decorator
0819b000-081bc000 rw-p 00000000 00:00 0 [heap]
b7433000-b7435000 rw-p 00000000 00:00 0
b7435000-b7476000 r-xp 00000000 08:01 656247 /lib/i386-linux-gnu/libm-2.17.so
b7476000-b7477000 r--p 00040000 08:01 656247 /lib/i386-linux-gnu/libm-2.17.so
b7477000-b7478000 rw-p 00041000 08:01 656247 /lib/i386-linux-gnu/libm-2.17.so
b7478000-b7625000 r-xp 00000000 08:01 656199 /lib/i386-linux-gnu/libc-2.17.so
b7625000-b7627000 r--p 001ad000 08:01 656199 /lib/i386-linux-gnu/libc-2.17.so
b7627000-b7628000 rw-p 001af000 08:01 656199 /lib/i386-linux-gnu/libc-2.17.so
b7628000-b762c000 rw-p 00000000 00:00 0
b762c000-b7647000 r-xp 00000000 08:01 656224 /lib/i386-linux-gnu/libgcc_s.so.1
b7647000-b7648000 r--p 0001a000 08:01 656224 /lib/i386-linux-gnu/libgcc_s.so.1
b7648000-b7649000 rw-p 0001b000 08:01 656224 /lib/i386-linux-gnu/libgcc_s.so.1
b7649000-b7725000 r-xp 00000000 08:01 1969970 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.17
b7725000-b7726000 ---p 000dc000 08:01 1969970 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.17
b7726000-b772a000 r--p 000dc000 08:01 1969970 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.17
b772a000-b772b000 rw-p 000e0000 08:01 1969970 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.17
b772b000-b7732000 rw-p 00000000 00:00 0
b7747000-b774b000 rw-p 00000000 00:00 0
b774b000-b774c000 r-xp 00000000 00:00 0 [vdso]
b774c000-b776c000 r-xp 00000000 08:01 656173 /lib/i386-linux-gnu/ld-2.17.so
b776c000-b776d000 r--p 0001f000 08:01 656173 /lib/i386-linux-gnu/ld-2.17.so
b776d000-b776e000 rw-p 00020000 08:01 656173 /lib/i386-linux-gnu/ld-2.17.so
bfa1a000-bfa3b000 rw-p 00000000 00:00 0 [stack]
Aborted (core dumped)
修改過適合 C++ 的作法
#include <string>
#include <iostream>
using namespace std;
class CComponent
{
public:
CComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual int value(void) = 0;
virtual string getInfo(void) = 0;
};
class CConcreteComponent : public CComponent
{
private:
int val;
public:
CConcreteComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
val = 10;
}
virtual ~CConcreteComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual int value(void)
{
return val;
}
virtual string getInfo(void)
{
return "CConcreteComponent";
}
};
class CDecorator : public CComponent
{
public:
CDecorator()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CDecorator()
{
cout << __PRETTY_FUNCTION__ << endl;
}
// new mothod
virtual void newMethod(void) = 0;
};
class CConcreteDecoratorA : public CDecorator
{
private:
CComponent *m_component;
public:
CConcreteDecoratorA(CComponent *c) : m_component(c)
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CConcreteDecoratorA()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual void newMethod(void)
{
}
// the same mothod but new behavior
virtual int value(void)
{
return 20 + m_component->value();
}
virtual string getInfo(void)
{
return m_component->getInfo() + " ,CConcreteDecoratorA";
}
};
修改過適合 C++ 的作法
#include <string>
#include <iostream>
using namespace std;
class CComponent
{
public:
CComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual int value(void) = 0;
virtual string getInfo(void) = 0;
};
class CConcreteComponent : public CComponent
{
private:
int val;
public:
CConcreteComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
val = 10;
}
virtual ~CConcreteComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual int value(void)
{
return val;
}
virtual string getInfo(void)
{
return "CConcreteComponent";
}
};
class CDecorator : public CComponent
{
public:
CDecorator()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CDecorator()
{
cout << __PRETTY_FUNCTION__ << endl;
}
// new mothod
virtual void newMethod(void) = 0;
};
class CConcreteDecoratorA : public CDecorator
{
private:
CComponent *m_component;
public:
CConcreteDecoratorA(CComponent *c) : m_component(c)
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CConcreteDecoratorA()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual void newMethod(void)
{
}
// the same mothod but new behavior
virtual int value(void)
{
return 20 + m_component->value();
}
virtual string getInfo(void)
{
return m_component->getInfo() + " ,CConcreteDecoratorA";
}
};
class CConcreteDecoratorB : public CDecorator
{
private:
CComponent *m_component;
public:
CConcreteDecoratorB(CComponent *c) : m_component(c)
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CConcreteDecoratorB()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual void newMethod(void)
{
}
// the same mothod but new behavior
virtual int value(void)
{
return 30 + m_component->value();
}
virtual string getInfo(void)
{
return m_component->getInfo() + " ,CConcreteDecoratorA";
}
};
int main()
{
CConcreteComponent m;
cout << endl;
CConcreteDecoratorA a(&m);
cout << endl;
CConcreteDecoratorB b(&a);
cout << "=============================================" << endl;
cout << "Info : " << m.getInfo() << endl;
cout << "Value: " <<m.value() << endl;
cout << "=============================================" << endl;
cout << "Info : " << a.getInfo() << endl;
cout << "Value: " << a.value() << endl;
cout << "=============================================" << endl;
cout << "Info : " << b.getInfo() << endl;
cout << "Value: " << b.value() << endl;
cout << "=============================================" << endl;
}
修正了動態配置所產生的 memory leak 的問題,但在使用上似乎不能向上例如此彈性。
用 shared_ptr 解決動態配置問題 (only supported by c++11)
#include <string>
#include <iostream>
#include <memory>
using namespace std;
class CComponent
{
public:
CComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual int value(void) = 0;
virtual string getInfo(void) = 0;
};
class CConcreteComponent : public CComponent
{
private:
int val;
public:
CConcreteComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
val = 10;
}
virtual ~CConcreteComponent()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual int value(void)
{
return val;
}
virtual string getInfo(void)
{
return "CConcreteComponent";
}
};
class CDecorator : public CComponent
{
public:
CDecorator()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual ~CDecorator()
{
cout << __PRETTY_FUNCTION__ << endl;
}
// new mothod
virtual void newMethod(void) = 0;
};
class CConcreteDecoratorA : public CDecorator
{
private:
shared_ptr<CComponent> m_component;
public:
CConcreteDecoratorA(shared_ptr<CComponent> c) : m_component(c)
{
cout << __PRETTY_FUNCTION__ << endl;
cout << "use count:" << c.use_count() << endl;
}
virtual ~CConcreteDecoratorA()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual void newMethod(void)
{
}
// the same mothod but new behavior
virtual int value(void)
{
return 20 + m_component->value();
}
virtual string getInfo(void)
{
return m_component->getInfo() + " ,CConcreteDecoratorA";
}
};
class CConcreteDecoratorB : public CDecorator
{
private:
shared_ptr<CComponent> m_component;
public:
CConcreteDecoratorB(shared_ptr<CComponent> c) : m_component(c)
{
cout << __PRETTY_FUNCTION__ << endl;
cout << "use count:" << c.use_count() << endl;
}
virtual ~CConcreteDecoratorB()
{
cout << __PRETTY_FUNCTION__ << endl;
}
virtual void newMethod(void)
{
}
// the same mothod but new behavior
virtual int value(void)
{
return 30 + m_component->value();
}
virtual string getInfo(void)
{
return m_component->getInfo() + " ,CConcreteDecoratorA";
}
};
int main()
{
shared_ptr<CComponent> m(new CConcreteComponent());
cout << "m's use count:" << m.use_count() << endl;
cout << endl;
shared_ptr<CComponent> a(new CConcreteDecoratorA(m));
cout << "a's use count:" << a.use_count() << endl;
cout << endl;
shared_ptr<CComponent> b(new CConcreteDecoratorB(m));
cout << "b's use count:" << b.use_count() << endl;
cout << "=============================================" << endl;
cout << "Info : " << m->getInfo() << endl;
cout << "Value: " << m->value() << endl;
cout << "=============================================" << endl;
cout << "Info : " << a->getInfo() << endl;
cout << "Value: " << a->value() << endl;
cout << "=============================================" << endl;
cout << "Info : " << b->getInfo() << endl;
cout << "Value: " << b->value() << endl;
cout << "=============================================" << endl;
}