比如现在我们有如下的几个类:
{
public :
~ CGShape();
virtual void Draw() = 0 ;
};
class CGRectangle : public CGShape
{
public :
void Draw();
};
class CGSquare : public CGShape
{
public :
void Draw();
};
class CGCircle : public CGShape
{
public :
void Draw();
};
如果现在有些代码的用户有一个特殊的需要,就是要在绘制出图形的时候同时把图形的中心点也绘制出来,那我们该怎么办呢?
很显然,不能直接给各个类的Draw方法中加上绘制中心点的代码,因为并不是所有的用户都需要这个功能。
那么我们可以给基类CGShape增添一个bool类型的成员变量m_bDrawCenter,并添加一个设置该变量值的公有方法SetDrawCenter,再在各个子类的Draw方法里面根据变量m_bDrawCenter的值来判断是否绘制中心点。需要绘制中心点的用户在调用Draw方法之前先调用SetDrawCenter方法把m_bDrawCenter设置为true。
还有一个方法,就是分别以类CGRectangle、CGSquare和CGCircle为基类继承,在各个子类中重载Draw方法,在该方法里面添加绘制中心点的代码。
上面两种方法都可行,可是我们来仔细分析一下这两种方法的缺陷:
方法一,每个类中的Draw方法中都要添加判断变量m_bDrawCenter的值的代码和绘制中心点的代码,这些代码在每个类中都是重复的,添加的工作也是非常枯燥无味。如果说类很多的话,那么做这个工作的程序员会崩溃的。最重要的一点是,如果上面那些类都是包含在库文件中,没有源代码,那么这个方法就根本行不通。
方法二,看起来似乎很符合面向对象设计(OOD),也不需要上面那些类的源代码。但是,这样会产生大量子类,并增加了类的层次结构。而且继承下来的每个子类也都是修改Draw方法,而且添加的绘制中心点的代码也都是重复的。
为了避免上面所说的各种缺陷,我们可以使用DECORATOR模式。看下面这个类:
{
public :
CGDrawShapeWithCenter(CGShape * pShape);
void Draw();
private :
CGShape * m_pShape;
};
CGDrawShapeWithCenter::CGDrawShapeWithCenter(CGShape * pShape)
{
// 得到指向具体图形的指针
m_pShape = pShape;
}
void CGDrawShapeWithCenter::Draw()
{
m_pShape -> Draw();
// 在这里添加绘制中心点的代码
}
这个类使用起来非常简单,下面这个函数就是绘制一个圆以及圆心:
{
CGCircle c ircle ;
CGDrawShapeWithCenter shape(&circle);
shape.Draw();
}
在类CGDrawShapeWithCenter中,我们通过一个指向CGShape的指针获得了要绘制的图形的控制权,用户在调用Draw方法时并没有觉得有什么不同。我们在即不会修改任何类,也不会产生大量子类,更不会有大量重复代码的情况下,满足了特殊用户的需求。
当然我上面举的这个例子非常简单,但是足以说明DECORATOR模式的优点。需要注意的一点就是,类CGDrawShapeWithCenter必须实现所有类CGShape的接口,在不需要修改的接口实现中只要调用指向CGShape的指针m_pShape相应的方法就行了。
现在,有人也许会问:为什么类CGDrawShapeWithCenter要从类CGShape继承?从上面的代码上来看,单独写一个类CGDrawShapeWithCenter也可以实现所有的功能。但是,请看下面这个函数:
{
pShape -> Draw();
}
这个函数是用户写来绘制图形的。如果类CGDrawShapeWithCenter不是从类CGShape继承,那么要在绘制图形的同时把图形的中心也绘制出来,就必须修改这个函数:
{
pShape -> Draw();
}
而如果类CGDrawShapeWithCenter是从类CGShape继承来的,用户就不用修改上面的函数。因为利用类的多态性,把一个类CGDrawShapeWithCenter对象的指针传给函数就行了。比如下面这样:
CGDrawShapeWithCenter shape( & circle);
DrawShape( & shape);
也就是说,所有用CGShape的地方都能用CGDrawShapeWithCenter,从而发挥C++类的多态性的强大功能。在这种情况下,用户代码的修改量也可以降到最小。而这样做最大的好处是decorator类CGDrawShapeWithCenter还能被其他decorator类来修饰。其实,DECORATOR模式最精妙的地方就是decorator类是从要修饰的类的基类继承,而且有一个指向被修饰类的指针的成员。