DECORATOR模式--《敏捷软件开发》读书笔记(二)

    比如现在我们有如下的几个类:

class  CGShape
{
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模式。看下面这个类:

class  CGDrawShapeWithCenter :  public  CGShape
{
public :
    CGDrawShapeWithCenter(CGShape 
* pShape);
    
void  Draw();

private :
    CGShape 
* m_pShape;
};

CGDrawShapeWithCenter::CGDrawShapeWithCenter(CGShape 
* pShape)
{
    
//  得到指向具体图形的指针
    m_pShape  =  pShape;
}

void  CGDrawShapeWithCenter::Draw()
{
    m_pShape
-> Draw();
    
//  在这里添加绘制中心点的代码
}

    这个类使用起来非常简单,下面这个函数就是绘制一个圆以及圆心:

void  DrawCircleWithCenter()
{
    CGCircle c
ircle ;
    CGDrawShapeWithCenter shape(&circle);
    shape.Draw();
}

    在类CGDrawShapeWithCenter中,我们通过一个指向CGShape的指针获得了要绘制的图形的控制权,用户在调用Draw方法时并没有觉得有什么不同。我们在即不会修改任何类,也不会产生大量子类,更不会有大量重复代码的情况下,满足了特殊用户的需求。
    当然我上面举的这个例子非常简单,但是足以说明DECORATOR模式的优点。需要注意的一点就是,类CGDrawShapeWithCenter必须实现所有类CGShape的接口,在不需要修改的接口实现中只要调用指向CGShape的指针m_pShape相应的方法就行了。
    现在,有人也许会问:为什么类CGDrawShapeWithCenter要从类CGShape继承?从上面的代码上来看,单独写一个类CGDrawShapeWithCenter也可以实现所有的功能。但是,请看下面这个函数:

void  DrawShape(CGShape  * pShape)
{
    pShape
-> Draw();
}

    这个函数是用户写来绘制图形的。如果类CGDrawShapeWithCenter不是从类CGShape继承,那么要在绘制图形的同时把图形的中心也绘制出来,就必须修改这个函数:

void  DrawShape(CGDrawShapeWithCenter  * pShape)
{
    pShape
-> Draw();
}

    而如果类CGDrawShapeWithCenter是从类CGShape继承来的,用户就不用修改上面的函数。因为利用类的多态性,把一个类CGDrawShapeWithCenter对象的指针传给函数就行了。比如下面这样:

CGCircle circle;
CGDrawShapeWithCenter shape(
& circle);
DrawShape(
& shape);

    也就是说,所有用CGShape的地方都能用CGDrawShapeWithCenter,从而发挥C++类的多态性的强大功能。在这种情况下,用户代码的修改量也可以降到最小。而这样做最大的好处是decorator类CGDrawShapeWithCenter还能被其他decorator类来修饰。其实,DECORATOR模式最精妙的地方就是decorator类是从要修饰的类的基类继承,而且有一个指向被修饰类的指针的成员。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值