zoukankan      html  css  js  c++  java
  • HeadFirst设计模式 之 C++实现(三):Decorator(装饰者模式)

    装饰者模式是非常有意思的一种设计模式,你将可以在不改动不论什么底层代码的情况下。给你的(或别人的)对象赋予新的职责。

    不是使用继承每回在编译时超类上改动代码,而是利用组合(composition)和托付(delegation)可以在执行时具有继承行为的效果。

    代码应该如同晚霞中的莲花一样地关闭(免于改变),如同晨曦中的莲花一样地开放(可以扩展)。

    这就是。设计原则之五:类应该对扩展开放,对改动关闭

    通常情况下。我们不会对代码的每一处设计都採用该原则,我们实在没有闲工夫把设计的每一个部分都这么设计(并且,就算做得到,也可能仅仅是一种浪费)。你须要把注意力集中在设计中最有可能改变的地方。然后应用开放-关闭原则


    装饰者模式,【动态地将责任附加到对象上】若要扩展功能,装饰者提供了比继承更有弹性的替代方案

    当然。这并不代表我们在设计类的时候不採用继承。装饰者和被装饰者必须是一样的类型,也就是有共同的超类。这是相当关键的地方。在这里,我们利用继承达到“类型匹配”,而不是利用继承获得“行为”。假设依赖继承,那么类的行为仅仅能在编译时静态决定。

    换句话说,行假设不是来自超类,就是子类覆盖后的版本号。

    反之,利用组合。能够把装饰者混合着用……并且是在“执行时”。

    以下我们来看星巴兹饮料的设计方案。四种饮料能够分别和不同数量不同种类的调料搭配起来销售给客户:


    装饰者一般是用其它类似于工厂或生成器这种模式创建的。

    组合和托付可用于在执行时动态地加上新的行为。

    然后是我自己用C++实现的星巴兹饮料模型(在实现中,我增加了:在菜单上加上咖啡的容量大小供客户选择,因此也须要考虑调料依据咖啡容量收费),有疏漏的地方请不吝赐教:

    // Decorator Patterm(装饰者设计模式)
    #include <iostream>
    #include <string>
    enum SIZE{Tall_SIZE, GRANDE_SIZE, RENTI_SIZE};
    using std::string;
    
    // 超类,ABC,抽象组件
    class Beverage
    {
    public:
    	Beverage();
    	virtual ~Beverage();
    	int getSize();		// 在实现饮料搭配调料的基础上,加入的新功能
    	void setSize(int sizeOfBeverge);	// 能够自主选择大中小杯。当然。价格也不一样哦~
    	virtual string & getDescription() = 0;
    	virtual float cost() = 0;
    protected:
    	string m_description;
    private:
    	SIZE m_size;
    };
    
    // 装饰类。抽象装饰
    class CondimentDecorator : public Beverage
    {
    public:
    	virtual string & getDescription();
    };
    
    // 详细的咖啡。继承自超类。详细组件
    class Espresso : public Beverage
    {
    public:
    	Espresso();
    	float cost();
    };
    
    class HouseBlend : public Beverage
    {
    public:
    	HouseBlend();
    	float cost();
    };
    // 另外两种饮料类(DarkRoast和Decaf)都是一样的
    
    // 调料,详细装饰
    class Mocha : public CondimentDecorator
    {
    private:
    	Beverage *m_beverage;
    public:
    	Mocha(Beverage * beverage);
    	string & getDescription();
    	float cost();
    };
    
    class Whip : public CondimentDecorator
    {
    private:
    	Beverage *m_beverage;
    public:
    	Whip(Beverage * beverage);
    	string & getDescription();
    	float cost();
    };
    

    DECORATOR—Mary过完轮到Sarly过生日。还是不要叫她自己挑了。不然这个月伙食费肯定玩完。拿出我去年在华山顶上照的照片,在背面写上“最好的的礼物。就是爱你的Fita”,再到街上礼品店买了个像框(卖礼品的MM也非常美丽哦)。再找隔壁搞美术设计的Mike设计了一个美丽的盒子装起来……我们都是Decorator,终于都在修饰我这个人呀,怎么样,看懂了吗?


      装饰模式:装饰模式以对client透明的方式扩展对象的功能,是继承关系的一个替代方案,提供比继承很多其它的灵活性。动态给一个对象添加功能。这些功能能够再动态的撤消。添加由一些基本功能的排列组合而产生的很大量的功能。
    // Decorator Patterm(装饰者设计模式)
    
    #include "DecoratorPattern.h"
    
    // 超类,ABC。抽象组件
    Beverage::Beverage()
    {
    	this->m_description = "Unknow Beverage";
    	m_size = RENTI_SIZE;
    }
    
    Beverage::~Beverage()
    {
    }
    
    string & Beverage::getDescription()
    {
    	return m_description;
    }
    
    int Beverage::getSize()
    {
    	return m_size;
    }
    
    // 输入0 - Tall_SIZE小杯,输入1 - GRANDE_SIZE中杯
    // 输入2 - RENTI_SIZE。输入others - 默认RENTI_SIZE大杯 
    void Beverage::setSize(int sizeOfBeverge)
    {
    	switch(sizeOfBeverge)
    	{
    		case Tall_SIZE:
    			m_size = Tall_SIZE;
    			break;
    		case GRANDE_SIZE:
    			m_size = GRANDE_SIZE;
    			break;
    		case RENTI_SIZE:
    		default:
    			m_size = RENTI_SIZE;
    			break;
    	}
    }
    // CondimentDecorator没有什么好实现的,构造和析构都用默认
    
    // 详细的咖啡,继承自超类,详细组件
    Espresso::Espresso()
    {
    	m_description = "Espresso Coffee";
    }
    
    float Espresso::cost()
    {
    	double allCost;
    	switch(getSize())
    	{
    		case Tall_SIZE:
    			allCost = 1.0;
    			break;
    		case GRANDE_SIZE:
    			allCost = 1.5;
    			break;
    		case RENTI_SIZE:
    		default:
    			allCost = 1.9;
    			break;
    	}
    	return allCost;
    }
    
    HouseBlend::HouseBlend()
    {
    	m_description = "HouseBlend Coffee";
    }
    
    float HouseBlend::cost()
    {
    	double allCost;
    	switch(getSize())
    	{
    		case Tall_SIZE:
    			allCost = .4;
    			break;
    		case GRANDE_SIZE:
    			allCost = .7;
    			break;
    		case RENTI_SIZE:
    		default:
    			allCost = .89;
    			break;
    	}
    	return allCost;
    }
    
    // 调料,详细的装饰类
    Mocha::Mocha(Beverage * beverage)
    {
    	m_beverage = beverage;
    }
    
    string & Mocha::getDescription()
    {
    	return m_beverage->getDescription() + ", Mocha";
    }
    
    float Mocha::cost()
    {	
    	double allcost = m_beverage->cost();
    	switch(m_beverage->getSize())
    	{
    		case Tall_SIZE:
    			allcost += .10;
    			break;
    		case GRANDE_SIZE:
    			allcost += .15;
    			break;
    		case RENTI_SIZE:
    		default:
    			allcost += .20;
    			break; 
    	}
    	return allcost;
    }
    
    Whip::Whip(Beverage * beverage)
    {
    	m_beverage = beverage;
    }
    
    string & Whip::getDescription()
    {
    	return m_beverage->getDescription() + ", Whip";
    }
    
    float Whip::cost()
    {
    	double allcost = m_beverage->cost();
    	switch(m_beverage->getSize())
    	{
    		case Tall_SIZE:
    			allcost += .15;
    			break;
    		case GRANDE_SIZE:
    			allcost += .20;
    			break;
    		case RENTI_SIZE:
    		default:
    			allcost += .25;
    			break; 
    	}
    	return allcost;
    }


    我们例如说,假设顾客想要双倍摩卡奶泡深焙咖啡中杯。实现例如以下(图表示的是摩卡和奶泡深焙咖啡的包括装饰结构):


    <pre name="code" class="cpp">
    
    int main()
    {
    	// 双倍摩卡奶泡深焙咖啡中杯
    	Beverage * beverage1 = new Espresso();
    	beverage1->setSize(GRANDE_SIZE);
    	beverage1 = new Mocha(beverage1);
    	beverage1 = new Mocha(beverage1);
    	beverage1 = new Whip(beverage1);
    	
    	delete beverage1;
    	return 0;
    }
    
    
    
    
    
    

    我相信大家都实用过PS,并且都了解过PS中图层的原理。当我们P图片时候使用图层能够实现非常多效果。并且假设我们认为当中一个图层效果不好看我们能够直接删除,而不影响其它图层,我们每次P出来的照片都是一层层图层的叠加得到的。

    这也是装饰者的一种可应用场景。

    当然。装饰者模式也有缺点:

    1、 装饰链不能过长。否则会影响效率。

    2、仅仅在必要的时候使用装饰者模式,装饰者会导致设计中出现很多小对象,假设过度使用,会让程序变得非常复杂。添加系统维护难度。


    转载请注明出处:http://blog.csdn.net/aall3210_tsingloon/article/details/28870771


  • 相关阅读:
    centos下nginx代理tomcat,使nginx同时支持php与jsp
    tomcat配置默认访问项目和HTTP端口号
    Nginx服务器之Nginx与tomcat结合访问jsp
    Windows下Nginx的启动、停止等命令
    bootstrap之navbar
    EL与JSTL
    用网页计数器来说明application和session
    cookie,session以及application的比较
    请求转发与重定向
    servlet 的生命周期
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/6848046.html
Copyright © 2011-2022 走看看