模式三:裝飾者模式(Decorator Pattern)——對象的功能擴展

  • 裝飾者模式

動態地將責任附加到對象上。若要擴展功能,裝飾者提供比繼承更有彈性的替代方案。

  • 應用分析——對象的功能擴展

對象的功能擴展,最簡單的方式就是繼承,但是幾種不同的功能有不同的組合時,將會產生許許多多的類,這樣不利於管理。採用裝飾者模式,讓裝飾者與實際對象有相同的接口(繼承同一抽象類),通過組合或委託的方式引用被裝飾對象,然後對被裝飾對象進行動態擴展,可以獲得更大的靈活性。

  • 實例分析——星巴克有各種咖啡:HouseBlend、DarkRoast、Decaf、Espresso,客戶購買時,可以要求加入各種調料,如:SteamedMilk、Soy、Mocha等等,星巴克會根據不同的調料進行收費,如果考慮用繼承實現,那麼類數將會爆發性增長,如果考慮使用標記變量,這可能是一個解決方案,但是不利於擴展,用裝飾者模式,可以巧妙解決這一問題。

  • 代碼分析

//Component.h
//公共接口
#ifndef COMPONENT_H
#define COMPONENT_H
#include <string>

class Component//被裝飾對象和裝飾者公共的接口
{
protected:
	std::string desc;
public:
	virtual std::string getdesc()
	{
		return desc;
	}
	virtual double cost()=0;
	virtual ~Component(){}
};

#endif


//ConcreteComponent.h
//被裝飾者
#ifndef CONCRETECOMPONENT_H
#define CONCRETECOMPONENT_H

#include "Component.h"

//兩種不同的咖啡
class HouseBlend:public Component
{
public:
	HouseBlend()
	{
		desc="HouseBlend";
	}
	double cost()
	{
		return 10.0;
	}
};

class DarkRoast:public Component
{
public:
	DarkRoast()
	{
		desc="DarkRoast";
	}
	double cost()
	{
		return 20.0;
	}
};


#endif


//Decorator.h
//裝飾者
#ifndef DECORATOR_H
#define DECORATOR_H

#include "Component.h"

//兩種調料
class Milk:public Component
{
private:
	Component *ptrCom;//被裝飾者
public:
	Milk(Component *ptrCom)
	{
		this->ptrCom=ptrCom;
	}
	std::string getdesc()
	{
		return ptrCom->getdesc()+", Milk";
	}
	double cost()
	{
		return ptrCom->cost()+5.0;
	}
};

class Mocha:public Component
{
private:
	Component *ptrCom;
public:
	Mocha(Component *ptrCom)
	{
		this->ptrCom=ptrCom;
	}
	std::string getdesc()
	{
		return ptrCom->getdesc()+", Mocha";
	}
	double cost()
	{
		return ptrCom->cost()+15.0;
	}
};

#endif


//main.cpp
//測試程序

#include <iostream>
#include "Decorator.h"
#include "ConcreteComponent.h"
#define print(x) std::cout<<x->getdesc()<<": $"<<x->cost()<<std::endl

int main()
{
	Component *HB=new HouseBlend();
	print(HB);
	Component *DR=new DarkRoast();
	print(DR);

	Component *HB_Milk=new Milk(HB);
	print(HB_Milk);
	Component *HB_Milk_M=new Mocha(HB_Milk);
	print(HB_Milk_M);

	Component *DR_M=new Mocha(DR);
	print(DR_M);

	delete HB;
	delete HB_Milk;
	delete HB_Milk_M;
	delete DR;
	delete DR_M;

	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章