装饰模式
什么是装饰模式?
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。
其实是对已经存在的某些类,动态地将功能附加到对象上面。
什么时候使用装饰模式呢?
1、需要扩展一个类的功能,或者给一个类附加职责。
2、需要动态的给一个对象添加功能,但是这些功能可以动态的撤销
3、需要增加由一些基本功能的排列组合而产生的非常大量的功能
4、不能采用子类扩充功能的时候。
装饰模式的优缺点
优点:
1、装饰模式比继承有更多的灵活性
2、可以使用不同的具体的装饰类以及装饰类的组合,创造出很多不同的行为。
缺点:
1、虽然比继承更灵活,但是比继承更复杂。
2、装饰模式有很多小类,过度使用会更复杂
3、装饰模式根据抽象组件编程,当针对具体组件需要考虑是否合适。
我们先来建立一个装饰模式。
我们平时去食堂吃饼的时候,一般就会加很多东西,然后老板根据你加的东西和手抓饼本身的价格来算钱。那些额外加的东西就可以当做装饰物。
1、先来看一下我们创建的装饰模式的类图
大家是不是很奇怪,为什么少了,Component(对象接口)类。其实是我这里没有把饼抽象化。这个时候可以直接将抽象装饰类继承具体的对象类就可以了。
2、开始写我们的代码
① 具体对象
class Cake//具体对象
{
public Cake()//构造函数——无参数的
{ }
private string name;
public Cake(string name)//构造函数——有参数的
{
this.name = name;
}
public virtual void Description()//描述饼的方法
{
Console.Write("装饰的{0}一共是", name);
}
public virtual double Cost()//算钱的方法,
{
return 3;//只要一个饼,3元
}
}
看到上面的两个构造函数,大家有没有产生一个疑问,为什么有2个构造函数呢?
因为实例化具体类的时候,需要有参数的构造函数,但是实例化具体装饰对象的时候是无参数的构造函数。
而类有一个默认的无参数的构造函数,可是当你一但重写有参数的构造函数,那个无参数会被覆盖,所以也要在建立一个无参数的构造函数。
② 抽象装饰类
class Meat:Cake//装饰品,肉类
{
protected Cake component;//建立一个受保护的具体对象
public void Decorate(Cake component)//装饰方法
{
this.component = component;
}
public override void Description()//重写描述方法
{
if(component !=null)//如果有被装饰的对象,那么执行被装饰对象的描述方法
{
component.Description();
}
}
public override double Cost()//重写算钱方法,这个里面我是没有去判断有没有被修饰的对象
{
return component.Cost();//返回被装饰对象的算钱方法
}
}
到这里的时候大家应该产生一个疑问,如果没有判断是否有修饰的对象会对代码的运行产生影响吗?
② 具体装饰对象类
class Egg:Meat//具体装饰对象-鸡蛋
{
public override void Description()//重写描述方法
{
Console.Write("鸡蛋");
base.Description();
}
public override double Cost()//重写算钱方法
{
return base.Cost() + 1.5;
}
}
class Ham : Meat//具体装饰对象-火腿
{
public override void Description()
{
Console.Write("火腿");
base.Description();
}
public override double Cost()
{
return base.Cost() + 1.5;
}
}
class Tenderloin : Meat//具体装饰对象-里脊
{
public override void Description()
{
Console.Write("里脊");
base.Description();
}
public override double Cost()
{
return base.Cost() + 2;
}
}
③ 客户端代码
//先实例化一些对象
Cake cake = new Cake("手抓饼");
Egg egg = new Egg();
Egg egg2 = new Egg();
Ham ham = new Ham();
Tenderloin tenderloin = new Tenderloin();
//装饰过程
egg.Decorate(cake);
ham.Decorate(egg);
tenderloin.Decorate(ham);
//调用描述,和算钱方法
tenderloin.Description();
Console.Write(tenderloin.Cost());
Console.ReadKey();
现在我们来分析一下客户端的代码:
实例化所需要对了具体对象然后在进行装饰。
将鸡蛋装饰到手抓饼上,然后讲火腿装饰到鸡蛋上,最后将里脊装饰到火腿上。
最后调用描述装扮和算钱的方法都是从最外层到最里层的。可以看图:
那我们来解释一下是怎么从tenderloin.Description()一步步调用到最手抓饼的。
而cost()方法与上图基本一致,但是我没有感觉到判断了是否修饰其他的物品,与不判断的区别。欢迎大家帮我解决这个问题。
④ 结果