装饰器模式 C++

装饰器模式(decorator)给一个对象动态地添加职责,而无需为了每一种可能的职责配置情况去创建特定的子类(派生类) 《代码大全》 第二版p102

当需要为一个类增加新功能,我们第一想法通常是通过继承。设想一个这样的例子,你在设计装修一个房间,你已经实现了许多的功能(类),比如这个类会为房间开个窗户,那个类会为房间挂一张画,这些类组合起来完成的功能就是最终房间的样子。

class getAWindow{
	void getWindow(){
	put a window on the wall.
	}
}

class getAPainting{
	void getPainting(){
	hang a painting in the room.

	}
}

class otherFunction  .......

那么要实现一个新的房间,你需要组合以上这些功能,如果用多重继承,那么需要给每一种组合都创造一个派生类,还得注意有没有函数重复定义。

class allFunc:publc getAWindow, getAPainting ... {
	//调用所有的函数
	do(){
		getWindow();
		getPainting();
	}

}

如果需求有一点改动,比如你要把墙刷成黄色,你创造的新类(你总不希望设计了那么久只用在一个房间里吧)当然可以直接从allFunc继承

class yellowWall:public allFunc{
	do2(){
		allFunc::do();

		brushyellow();
	}
	
}

到这里貌似还没有出现什么问题,只要每次增加一个功能建立一个派生类就行了,但是如果出现了这样一个需求,用户很喜欢你的整套设计,唯独不喜欢地上那张桌子。。

怎么办? 貌似可以在allFunc里把 desk相关操作删掉就行了,但是别忘了,还有其他的房间(已经实例化的对象)使用了这个类,牵一发而动全身啊。
没办法,只能重新建立一个复杂度和allFunc一个的类了,只是为了删除一个功能, 这就是多重继承的局限性。

装饰器模式可以很好的应用在许多功能组合的场景,大概的可以描述为 一个新的类 = 旧的类 + 新操作。

看一个经典的水果篮子的例子

class Basket{
public:
    virtual void show() = 0;
    //普通函数, 既继承接口,又继承具体实现
    int &getValue(){
        return value;
    }
    int value = 0;
};


class OriginBasket:public Basket{
public:
    void show(){
        std::cout<<"this is origin basket, value  = "<<value<<std::endl;
    }
};

class AppleBasket:public Basket{
public:
    AppleBasket(Basket *b){
        basket = b;
    }
    void show(){
        basket->show();
        std::cout<<"this is apple basket, value = "<<value<<std::endl;
    }
private:
    Basket* basket;
};

class PearBasket:public Basket{
public:
    PearBasket(Basket *b){
        basket = b;
    }
    void show(){
        basket->show();
        std::cout<<"this is pear basket, value= "<<value<<std::endl;
    }
    
private:
    Basket* basket;
};

   Basket * AppleAndPear = new PearBasket(
    		 					new AppleBasket(new 
     		OriginBasket));
    AppleAndPear->show();
    
   

显示结果

this is origin basket, value  = 0
this is apple basket, value = 0
this is pear basket, value= 0

可以看出,装饰类是在已有类的基础上包裹一次得到的,很像一个函数列,需要什么功能,只需要将它们组合起来就得到了。

小插曲:

 AppleAndPear->getValue() = 20;
 AppleAndPear->show();
 
//打印结果
this is origin basket, value  = 0
this is apple basket, value = 0
this is pear basket, value= 20

发现origin里的value值没有改,想来也是,三个类里都有分别从基类中继承得到了一个value值,也都有getValue方法来改变这个值,但是从高级类指针pear baskt是无法访问到 origin basket 的值的,只能改变自己的value,层级关系如下:

层级关系

有人想,对象数据成员里有低级对象的指针啊,可以根据指针访问啊。
AppleAndPear->basket->basket->getValue() = 20;
如果非要访问也不是不可以,那么要突破两个障碍。

  1. 这是个private 成员, 你把它弄成public就失去了封装的意义了。
  2. AppleAndPear->basket 指针在类中被声明为 Basket* 类型,通过它去访问 basket变量是行不通的,当然你可以把它强制转换为 AppleBasket* 类型的,但是一来不提倡将基类指针强制转换为派生类,二来,如果层级数量很多会变得非常复杂。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值