大話設計模式學習筆記-裝飾模式
裝飾模式
動態地給一個物件新增一些額外的職責,就增加功能來說,裝飾模式比生成子類更為靈活。
裝飾模式結構演示
元件類:Component
Component是定義一個物件介面,可以給這些物件動態地新增職責。
abstract class Component{ public abstract void Operation(); }
具體元件類:ConcreteComponent
ConcreteComponent是定義了一個具體的物件,也可以給這個物件新增一些職責。
class ConcreteComponent : Component{ publicoverride 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(c); //最後再執行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(); } }
輸出結果:控制檯
第一種裝扮:
棒球帽 球鞋 裝扮的小明
第二種裝扮:
太陽鏡 拖鞋 裝扮的小明
裝飾模式總結
裝飾模式是為已有功能動態新增更多功能的一種方式。
當系統需要新功能時,是向舊的類中新增新的程式碼。這些新的程式碼通常裝飾了原有類的核心職責或主要行為。
他們在主類中加入新的欄位、方法和邏輯,從而增加了主類的複雜度。
而這些新加入的東西僅僅是為了滿足一些之在某種特定情況下才會執行的特殊行為的需要。
裝飾模式提供了一個非常好的解決方案,把每個要裝飾的功能放在單獨的類中,並讓這個類包裝她所需要裝飾的物件。
因此當需要執行特殊行為時,客戶程式碼就可以執行時根據需要有選擇地按順序地使用裝飾功能包裝物件了。
裝飾模式的優點
把類中的裝飾功能從類中搬移出去,簡化原有的類。
有效地把核心職責和裝飾功能區分開來,而且可以去除相關類中重複的裝飾邏輯。