装饰模式

什么是装饰模式?

动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。
其实是对已经存在的某些类,动态地将功能附加到对象上面。

什么时候使用装饰模式呢?

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()方法与上图基本一致,但是我没有感觉到判断了是否修饰其他的物品,与不判断的区别。欢迎大家帮我解决这个问题。
④ 结果
装饰模式