大话设计模式-装饰模式
装饰模式
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
装饰模式结构演示
组件类:Component
Component是定义一个对象接口,可以给这些对象动态地添加职责。
abstract class Component{ public abstract void Operation(); }
具体组件类:ConcreteComponent
ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责。
class ConcreteComponent : Component{ public override void Operation() => Console.WriteLine("具体对象的操作"); }
装饰抽象类:Decorator
继承了Component,从外类来扩展Component类的功能,但对于Component来说是无需知道Decorator的存在的。
abstract class Decorator:Component{ protected Component component; //设置组件 public void SetComponent(Component component) => this.component = component; //重写方法为调用组件的原方法 public override void Operation()=>component?.Operation(); }
具体装饰类:ConcreteDecorator
ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。
class ConcreteDecoratorA : Decorator{ //装饰A独有的字段 private string addedState; public override void Operation(){ base.Operation(); addedState = "New State"; Console.WriteLine($"{addedState}是具体装饰对象A的操作"); } } class ConcreteDecoratorB : Decorator{ public override void Operation(){ base.Operation(); AddedBehavior(); Console.WriteLine("AddedBehavior是具体装饰对象B的操作"); } //装饰B对独有的方法 private void AddedBehavior() { } }
测试类:Program
class Program{ static void Main(string[] args){ //首先用ConcreteComponent实例化c var c = new ConcreteComponent(); var d1 = new ConcreteDecoratorA(); var d2 = new ConcreteDecoratorB(); //然后用ConcreteDecoratorA的实例化对象d1来包装c d1.SetComponent(c); //然后用ConcreteDecoratorB的实例化对象d2来包装d1 d2.SetComponent(d1); //最后再执行d2的Operation方法 d2.Operation(); Console.ReadKey(); } }
测试结果:控制台
具体对象的操作
New State是具体装饰对象A的操作
AddedBehavior是具体装饰对象B的操作
装饰模式是利用SetComponent来对对象进行包装的,这样每个装饰对象的实现就和如何使用这个对象分离开了,每个对象只关心自己的功能,不需要关心如何被添加到对象链当中。
如果只有一个ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类。
同理如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator的自认合并成一个类。
穿衣扮靓
人类:Person(ConcreteComponent)
class Person{ private string name; public Person() { } public Person(string name) => this.name = name; public virtual void Show() => Console.WriteLine($"装扮的{name}"); }
服饰类:Finery(Decorator)
class Finery : Person{ protected Person component; public void Decorate(Person component) => this.component = component; public override void Show()=>component?.Show(); }
具体服饰类:Sneakers、Slipper、Baseballcap、Sunglasses(ConcreteDecorator)
} class Sneakers : Finery{ public override void Show(){ Console.Write("球鞋 "); base.Show(); } } class Slipper : Finery{ public override void Show(){ Console.Write("拖鞋 "); base.Show(); } } class Baseballcap : Finery{ public override void Show(){ Console.Write("棒球帽 "); base.Show(); } } class Sunglasses : Finery{ public override void Show(){ Console.Write("太阳镜 "); base.Show(); } }
测试类:Program
class Program{ static void Main(string[] args){ var p = new Person("小明"); Console.WriteLine("第一种装扮:"); var sn = new Sneakers(); var bc = new Baseballcap(); sn.Decorate(p); bc.Decorate(sn); bc.Show(); Console.WriteLine("第二种装扮:"); var sl = new Slipper(); var sg = new Sunglasses(); sl.Decorate(p); sg.Decorate(sl); sg.Show(); Console.ReadKey(); } }
输出结果:控制台
第一种装扮:
棒球帽 球鞋 装扮的小明
第二种装扮:
太阳镜 拖鞋 装扮的小明
装饰模式总结
装饰模式是为已有功能动态添加更多功能的一种方式。
当系统需要新功能时,是向旧的类中添加新的代码。这些新的代码通常装饰了原有类的核心职责或主要行为。
他们在主类中加入新的字段、方法和逻辑,从而增加了主类的复杂度。
而这些新加入的东西仅仅是为了满足一些之在某种特定情况下才会执行的特殊行为的需要。
装饰模式提供了一个非常好的解决方案,把每个要装饰的功能放在单独的类中,并让这个类包装她所需要装饰的对象。
因此当需要执行特殊行为时,客户代码就可以运行时根据需要有选择地按顺序地使用装饰功能包装对象了。
装饰模式的优点
把类中的装饰功能从类中搬移出去,简化原有的类。
有效地把核心职责和装饰功能区分开来,而且可以去除相关类中重复的装饰逻辑。