装饰者模式么,在生活中我们是经常接触的。比如像我们这么快节奏的生活,好多都是早上去买煎饼。一般我们会这么说:“来一个粗粮煎饼,加两个鸡蛋,加一根肠”
或者:“来个山东煎饼,只加土豆丝”等等。“煎饼” 就是这个么个有弹性的对象,面饼是不变的,其它的像鸡蛋,肠什么的者在装饰面饼。这个也是我们编程时的一个设计原则
对扩展开放,对修改关闭。(在最后我会给出C# 和C++ 两种代码示例)
装饰者模式和“煎饼”差不多,它可以动态地将责任("鸡蛋“、“肠”...)附加到对象(”煎饼“)上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
我们看一下装饰者模式的类图:
看这个类图我们可以总结一下装饰者模式的特点:
1.被装饰对象和装饰品有相同的接口。这样装饰品和被装饰对象就可以相互交互。
2.装饰品对象包含一个被装饰对象的引用。
让我们做一个煎饼吧:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DecoratorDemo
{
[Flags]
public enum BcType
{
None = 0, // 0
SdCakeType, // 山东煎饼
EggType, // 蛋
SausageType // 肠
}
public interface IBatterCake
{
List<BcType> Type();
double Coast();
}
public class NoneBatterCake : IBatterCake
{
public List<BcType> Type()
{
return new List<BcType> {BcType.None};
}
public double Coast()
{
return 0;
}
}
/// <summary>
/// 山东煎饼
/// </summary>
public class SdBatterCake : IBatterCake
{
public List<BcType> Type()
{
return new List<BcType> {BcType.SdCakeType};
}
public double Coast()
{
return 3.5;
}
}
/// <summary>
/// 鸡蛋
/// </summary>
public class Egg : IBatterCake
{
private readonly IBatterCake _batterCake = new NoneBatterCake();
public Egg(IBatterCake mMoney)
{
_batterCake = mMoney;
}
public List<BcType> Type()
{
List<BcType> types = _batterCake.Type();
types.AddRange(new List<BcType>() { BcType.EggType });
return types;
}
public double Coast()
{
return 1 + _batterCake.Coast();
}
}
/// <summary>
/// 肠
/// </summary>
public class Sausage : IBatterCake
{
private readonly IBatterCake _batterCake = new NoneBatterCake();
public Sausage(IBatterCake mMoney)
{
_batterCake = mMoney;
}
public List<BcType> Type()
{
List<BcType> types = _batterCake.Type();
types.AddRange(new List<BcType>() { BcType.SausageType });
return types;
}
public double Coast()
{
return 2 + _batterCake.Coast();
}
}
/// <summary>
/// 计算花费
/// </summary>
public class CalculateMoney : IBatterCake
{
private readonly IBatterCake _batterCake = new NoneBatterCake();
public CalculateMoney(IBatterCake mMoney)
{
_batterCake = mMoney;
}
public List<BcType> Type()
{
return new List<BcType> {BcType.None};
}
public string Description()
{
List<BcType> types = _batterCake.Type();
int eggs = 0, sausage = 0,battercakies = 0;
for (int index = 0, count = types.Count(); index < count; index++)
{
if (types[index] == BcType.SdCakeType)
battercakies++;
if (types[index] == BcType.EggType)
eggs++;
if (types[index] == BcType.SausageType)
sausage++;
}
StringBuilder description = new StringBuilder();
if (battercakies > 0)
description.Append("煎饼").Append(battercakies).Append("个").Append("\n");
if (eggs > 0)
description.Append("鸡蛋").Append(eggs).Append("个").Append("\n");
if (sausage > 0)
description.Append("烤肠").Append(sausage).Append("个").Append("\n");
return description.ToString();
}
public double Coast()
{
return _batterCake.Coast();
}
}
public class Program
{
private static void Main(string[] args)
{
// 一个山东煎饼
IBatterCake sdBatterCake = new SdBatterCake();
// 一个鸡蛋
IBatterCake egg1 = new Egg(sdBatterCake);
// 再来个鸡蛋
IBatterCake egg2 = new Egg(egg1);
// 再来个肠
IBatterCake sausage = new Sausage(egg2);
CalculateMoney calculateMoney = new CalculateMoney(sausage);
Console.WriteLine(calculateMoney.Description());
Console.WriteLine("共花费 : {0}", calculateMoney.Coast());
Console.ReadLine();
}
}
}
看一下结果:
#include <iostream>
#include <string>
#include <list>
using namespace std;
enum class BcType
{
None = 0, // 0
SdCakeType, // 山东煎饼
EggType, // 蛋
SausageType // 肠
};
class IBatterCake
{
public:
virtual ~IBatterCake() {}
virtual list<BcType> type() const = 0;
virtual double coast() const = 0;
};
class NoneBatterCake : public IBatterCake
{
public:
NoneBatterCake() {}
virtual ~NoneBatterCake() { }
virtual list<BcType> type() const override
{
return list<BcType>{ BcType::None };
}
virtual double coast() const override
{
return 0;
}
};
/// <summary>
/// 山东煎饼
/// </summary>
class SdBatterCake : public IBatterCake
{
public:
SdBatterCake() {}
virtual ~SdBatterCake() { }
virtual list<BcType> type() const override
{
return list<BcType>{ BcType::SdCakeType };
}
virtual double coast() const override
{
return 3.5;
}
};
/// <summary>
/// 鸡蛋
/// </summary>
class Egg : public IBatterCake
{
public:
Egg() {}
Egg(IBatterCake *batter)
{
if (m_batter)
delete m_batter;
m_batter = batter;
}
~Egg()
{
delete m_batter;
}
virtual list<BcType> type() const override
{
list<BcType> ls = m_batter->type();
ls.push_back(BcType::EggType);
return ls;
}
virtual double coast() const override
{
return 3.5 + m_batter->coast();
}
private:
IBatterCake *m_batter = new NoneBatterCake();
};
/// <summary>
/// 肠
/// </summary>
class Sausage: public IBatterCake
{
public:
Sausage() {}
Sausage(IBatterCake *batter)
{
if (m_batter)
delete m_batter;
m_batter = batter;
}
~Sausage()
{
delete m_batter;
}
virtual list<BcType> type() const override
{
list<BcType> ls = m_batter->type();
ls.push_back(BcType::SausageType);
return ls;
}
virtual double coast() const override
{
return 2 + m_batter->coast();
}
private:
IBatterCake *m_batter = new NoneBatterCake();
};
/// <summary>
/// 计算花费
/// </summary>
class CalculateMoney : public IBatterCake
{
public:
CalculateMoney(IBatterCake *batter)
{
if (m_batter)
delete m_batter;
m_batter = batter;
}
~CalculateMoney()
{
delete m_batter;
}
virtual list<BcType> type() const override
{
return list<BcType>{ BcType::None };
}
string description()
{
list<BcType> types = m_batter->type();
int eggs = 0, sausage = 0, battercakies = 0;
for (const BcType &type : types) {
if (type == BcType::SdCakeType)
battercakies++;
if (type == BcType::EggType)
eggs++;
if (type == BcType::SausageType)
sausage++;
}
string description;
if (battercakies > 0)
description.append("煎饼").append(std::to_string(battercakies)).append("个\n");
if (eggs > 0)
description.append("加").append(std::to_string(eggs)).append("个鸡蛋\n");
if (sausage > 0)
description.append("加").append(std::to_string(sausage)).append("个烤肠\n");
return description;
}
virtual double coast() const override
{
return m_batter->coast();
}
private:
IBatterCake *m_batter = new NoneBatterCake();
};
int main()
{
IBatterCake *sdBatterCake = new SdBatterCake();
IBatterCake *egg1 = new Egg(sdBatterCake);
IBatterCake *egg2 = new Egg(egg1);
IBatterCake *sausage = new Sausage(egg2);
CalculateMoney *calculateMoney = new CalculateMoney(sausage);
cout << calculateMoney->description();
delete calculateMoney;
cin.get();
return 0;
}
结果是一样的
以下情况使用Decorator模式
1. 需要扩展一个类的功能,或给一个类添加附加职责。
2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。