今天学习了大话设计模式中的装饰模式,对这个模式的理解是在手动敲了代码之后第三遍看代码的时候才懂得的。我的心得就是,装饰模式===>包裹模式。呵呵,包裹模式是我起的名字,我的理解是装饰模式就是一层一层不断地往被装饰的对象上包裹上新的东西。
好了,现在说说装饰模式,并来印证一下我的“包裹模式”的说法,哈哈。
装饰模式的(Decorater):动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更灵活。【DP】这是从大话上抄的定义。下面是抄的类图:
加上注释的代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 装饰模式
{
/// <summary>
/// 定义一个对象接口,规定这些对象都要有Operation()方法
/// </summary>
abstract class Component
{
public abstract void Operation();
}
/// <summary>
/// 具体的对象类
/// </summary>
class ConcreteComponent : Component
{
public override void Operation()
{
Console.WriteLine("具体对象的操作");
}
}
/// <summary>
/// 装饰抽象类,继承自对象接口
///
/// 装饰者类与Component类既是继承关系,又是聚合关系
///
/// 在这个类中重写Operation(),实际上还是执行传入的Component对象的Operation(),
/// 这样才能实现一层一层的包装传入的Component,赋予其新功能
/// </summary>
abstract class Decorator : Component
{
protected Component component;
public void SetComponent(Component component)
{
this.component = component;
}
//在这个类中重写Operation(),实际上还是执行传入的Component对象的Operation()
public override void Operation()
{
if (component != null)
{
component.Operation();
}
}
}
/// <summary>
/// 具体的装饰类
/// </summary>
class ConcreteDecoretorA : Decorator
{
private string addedstate;
/// <summary>
///重写Operation()
//首先调用父类的Operation(),然后增加新的内容(功能),------->也可以先进行增加新的内容的操作,再调用父类的Operation()
/// </summary>
public override void Operation()
{
base.Operation();
addedstate = "New State";
Console.WriteLine("具体装饰对象A的操作");
}
}
class ConcreteDecoretorB : Decorator
{
public override void Operation()
{
base.Operation();
AddedBehavior();
Console.WriteLine("具体装饰对象B的操作");
}
private void AddedBehavior()
{
Console.WriteLine("具体修饰类B独有的方法");
}
}
/// <summary>
/// 客户端使用方法
/// </summary>
class Program
{
static void Main(string[] args)
{
ConcreteComponent c = new ConcreteComponent();//实例化一个具体的对象,这就是要被装饰的原始对象
ConcreteDecoretorA d1 = new ConcreteDecoretorA();//实例化一个具体装饰类A
ConcreteDecoretorB d2 = new ConcreteDecoretorB();//实例化一个具体装饰类B
d1.SetComponent(c);//将c赋予d1的component字段,完成d1对c的包装
d2.SetComponent(d1);//将d1赋予d2的component字段,完成d1对c的第二次包装,此处有为重要,不能传c
d2.Operation();//执行最后进行包装工作的对象的Operation()方法,这里的执行顺序是理解这个模式的关键,最好使用f11跟一下。
Console.Read();
}
}
}
下载版:https://files.cnblogs.com/yuanyuan/%e8%a3%85%e9%a5%b0%e6%a8%a1%e5%bc%8f.rar
执行结果:
这个的示例的执行过程用文字描述如下:
首先是对象实例化和具体装饰类内部字段的赋值:
ConcreteComponent c = new ConcreteComponent();//实例化一个具体的对象,这就是要被装饰的原始对象
ConcreteDecoretorA d1 = new ConcreteDecoretorA();//实例化一个具体装饰类A
ConcreteDecoretorB d2 = new ConcreteDecoretorB();//实例化一个具体装饰类B
d1.SetComponent(c);//将c赋予d1的component字段,完成d1对c的包装
d2.SetComponent(d1);//将d1赋予d2的component字段,完成d1对c的第二次包装,此处尤为重要,不能传c
经过两次包装,可以用如下示意图表示:
下面开始执行具体的显示命令
d2.Operation();//执行最后进行包装工作的对象的Operation()方法,这里的执行顺序是理解这个模式的关键,最好使用f11跟一下。
当执行d2.Operation()时执行的是ConcreteDecoretorB中的如下代码:
public override void Operation()
{
base.Operation();
AddedBehavior();
Console.WriteLine("具体装饰对象B的操作");
}
首先执行父类Decorator的Operation(),即如下代码:
public override void Operation()
{
if (component != null)
{
component.Operation();
}
}
这个过程首先找到b2的component字段,执行它的Operation()
b2的component是b1,于是执行b1的Operation(),即如下代码:
/// <summary>
///重写Operation()
//首先调用父类的Operation(),然后增加新的内容(功能),------->也可以先进行增加新的内容的操作,再调用父类的Operation()
/// </summary>
public override void Operation()
{
base.Operation();
addedstate = "New State";
Console.WriteLine("具体装饰对象A的操作");
}
b1的Operation()也是首先找到b1的component字段c,然后执行c的Operation()
public override void Operation()
{
Console.WriteLine("具体对象的操作");
}
于是输出第一行文字:具体对象的操作。
然后,为b1的私有字段赋了值,并输出:具体装饰对象A的操作。
至此,完成了b1的Operation()。
继续执行b2的Operation(),执行的是b2的私有方法:AddedBehavior(),输出了:具体修饰类B独有的方法。
最后输出:具体装饰对象B的操作。
由此可见,装饰模式的装饰过程是通过将被装饰对象赋给具体装饰类实例的内部字段component,实现对被装饰对象一层一层包装的。而显示过程是通过具体装饰类对抽象装饰父类的Operation()方法的类似递归引用(而这种类似递归的过程是通过引用内部字段component的Operation()实现的,所以Decorator与Concrete Compnent类必须继承自一个父类,或者Decorator直接继承ConcreteCompnent)的方式,实现一层一层的显示出具体装饰类对被修饰对象的包装结果的。
做一下总结:
1.ConcreteComponent与Decorator类必须继承自同一抽象父类,或让ConcreteCompnenet直接作为Decoratior的父类。
2.Decorator类中有ConcreteComponent类型的字段
3.ConcreteDecorator类中重写父类Operation()时需要使用base.Operation()调用父类的Operation()。
本文的一些心得为作者原创,希望能给你帮助,大家共同进步。虽然不是高深见解,也是费了作者一番心血,希望您在转载的时候能够保留原文链接。