装饰模式【设计模式学习-03】
Definition
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.?
Frequency of use:??Medium裝飾模式的UML類圖如下:
?
一個生動的例子:Pizza(手抓餅)
?
Component:
namespace DecoratorDemo {public abstract class Pizza{public string Description { get; set; }public abstract string GetDescription();public abstract double CalculateCost();} }?
ConcreteComponent:
using System;namespace DecoratorDemo {public class LargePizza : Pizza{public LargePizza(){Description = "Large Pizza";}public override string GetDescription(){return Description;}public override double CalculateCost(){return 9.00;}} }using System;namespace DecoratorDemo {public class MediumPizza : Pizza{public MediumPizza(){Description = "Medium Pizza";}public override string GetDescription(){return Description;}public override double CalculateCost(){return 6.00;}} }using System;namespace DecoratorDemo {public class SmallPizza : Pizza{public SmallPizza(){Description = "Small Pizza";}public override string GetDescription(){return Description;}public override double CalculateCost(){return 3.00;}} }Decorator
using System;namespace DecoratorDemo {public class PizzaDecorator : Pizza{protected Pizza _pizza;public PizzaDecorator(Pizza pizza){_pizza = pizza;}public override string GetDescription(){return _pizza.Description;}public override double CalculateCost(){return _pizza.CalculateCost();}} }ConcreteDecorator:
using System;namespace DecoratorDemo {public class Cheese : PizzaDecorator{public Cheese(Pizza pizza): base(pizza){Description = "Cheese";}public override string GetDescription(){return String.Format("{0}, {1}", _pizza.GetDescription(), Description);}public override double CalculateCost(){return _pizza.CalculateCost() + 1.25;}} }using System;namespace DecoratorDemo {public class Ham : PizzaDecorator{public Ham(Pizza pizza): base(pizza){Description = "Ham";}public override string GetDescription(){return String.Format("{0}, {1}", _pizza.GetDescription(), Description);}public override double CalculateCost(){return _pizza.CalculateCost() + 1.00;}} }using System;namespace DecoratorDemo {public class Peppers : PizzaDecorator{public Peppers(Pizza pizza): base(pizza){Description = "Peppers";}public override string GetDescription(){return String.Format("{0}, {1}", _pizza.GetDescription(), Description);}public override double CalculateCost(){return _pizza.CalculateCost() + 2.00;}} }?
Program:
using System;namespace DecoratorDemo {class Program{static void Main(string[] args){Pizza largePizza = new LargePizza();largePizza = new Cheese(largePizza);largePizza = new Ham(largePizza);largePizza = new Peppers(largePizza);Console.WriteLine(largePizza.GetDescription());Console.WriteLine("{0:C2}", largePizza.CalculateCost());Console.ReadKey();}} }DebugLZQ: ?手抓餅+奶酪+火腿+辣醬
?
通過使用裝飾模式,可以在運行時動態地擴充一個類的功能。
原理是:增加一個修飾類包裹原來的類。裝飾類實現新的功能,但是,在不需要用到新功能的地方,它可以直接調用原來的類中的方法。修飾類必須和原來的類有相同的接口。
修飾模式是類繼承的另外一種選擇。類繼承在編譯時候增加行為,而裝飾模式是在運行時增加行為。
當有幾個相互獨立的功能需要擴充時,這個區別就變得很重要。在有些面向對象的編程語言中,類不能在運行時被創建,通常在設計的時候也不能預測到有哪幾種功能組合。這就意味著要為每一種組合創建一個新類。相反,修飾模式是面向運行時候的對象實例的,這樣就可以在運行時根據需要進行組合。
其示例性代碼:
using System;namespace DoFactory.GangOfFour.Decorator.Structural {/// <summary>/// MainApp startup class for Structural /// Decorator Design Pattern./// </summary>class MainApp{/// <summary>/// Entry point into console application./// </summary>static void Main(){// Create ConcreteComponent and two DecoratorsConcreteComponent c = new ConcreteComponent();ConcreteDecoratorA d1 = new ConcreteDecoratorA();ConcreteDecoratorB d2 = new ConcreteDecoratorB();// Link decorators d1.SetComponent(c);d2.SetComponent(d1);d2.Operation();// Wait for user Console.ReadKey();}}/// <summary>/// The 'Component' abstract class/// </summary>abstract class Component{public abstract void Operation();}/// <summary>/// The 'ConcreteComponent' class/// </summary>class ConcreteComponent : Component{public override void Operation(){Console.WriteLine("ConcreteComponent.Operation()");}}/// <summary>/// The 'Decorator' abstract class/// </summary>abstract class Decorator : Component{protected Component component;public void SetComponent(Component component){this.component = component;}public override void Operation(){if (component != null){component.Operation();}}}/// <summary>/// The 'ConcreteDecoratorA' class/// </summary>class ConcreteDecoratorA : Decorator{public override void Operation(){base.Operation();Console.WriteLine("ConcreteDecoratorA.Operation()");}}/// <summary>/// The 'ConcreteDecoratorB' class/// </summary>class ConcreteDecoratorB : Decorator{public override void Operation(){base.Operation();AddedBehavior();Console.WriteLine("ConcreteDecoratorB.Operation()");}void AddedBehavior(){}} } View Code?
下面再給出一個示例程序,來自程杰的大話設計模式:
View Code using System;using System.Collections.Generic;
using System.Text;
namespace 裝飾模式
{
class Program
{
static void Main(string[] args)
{
Person xc = new Person("小菜");
Console.WriteLine("\n第一種裝扮:");
Sneakers pqx = new Sneakers();
BigTrouser kk = new BigTrouser();
TShirts dtx = new TShirts();
pqx.Decorate(xc);
kk.Decorate(pqx);
dtx.Decorate(kk);
dtx.Show();
Console.WriteLine("\n第二種裝扮:");
LeatherShoes px = new LeatherShoes();
Tie ld = new Tie();
Suit xz = new Suit();
px.Decorate(xc);
ld.Decorate(px);
xz.Decorate(ld);
xz.Show();
Console.WriteLine("\n第三種裝扮:");
Sneakers pqx2 = new Sneakers();
LeatherShoes px2 = new LeatherShoes();
BigTrouser kk2 = new BigTrouser();
Tie ld2 = new Tie();
pqx2.Decorate(xc);
px2.Decorate(pqx);
kk2.Decorate(px2);
ld2.Decorate(kk2);
ld2.Show();
Console.Read();
}
}
//Person類
class Person
{
public Person()
{ }
private string name;
public Person(string name)
{
this.name = name;
}
public virtual void Show()
{
Console.WriteLine("裝扮的{0}", name);
}
}
//裝飾類
class Finery : Person
{
protected Person component;
//打扮
public void Decorate(Person component)
{
this.component = component;
}
public override void Show()
{
if (component != null)
{
component.Show();
}
}
}
//具體裝飾類
class TShirts : Finery
{
public override void Show()
{
Console.Write("大T恤 ");
base.Show();
}
}
class BigTrouser : Finery
{
public override void Show()
{
Console.Write("垮褲 ");
base.Show();
}
}
class Sneakers : Finery
{
public override void Show()
{
Console.Write("破球鞋 ");
base.Show();
}
}
class Suit : Finery
{
public override void Show()
{
Console.Write("西裝 ");
base.Show();
}
}
class Tie : Finery
{
public override void Show()
{
Console.Write("領帶 ");
base.Show();
}
}
class LeatherShoes : Finery
{
public override void Show()
{
Console.Write("皮鞋 ");
base.Show();
}
}
}
?
使用裝飾模式需要注意的地方:
◇在發生“類爆炸”的情況下,應及時反思工程的設計;
◇在類中,不要過多的將“是否具有某種裝飾”用boolean來表示;
◇Decorator(裝飾)模式的關鍵在于“動態地實現功能擴展”;
◇裝飾器的安裝順序很重要,應努力做到裝飾器的安裝順序不影響最終的裝飾效果。
?
應用實例:
裝備大兵!無任何裝備時(核心功能)可以用拳腳搏擊;裝備了步槍,可以正常射擊;裝備了重機槍,可以掃射;裝備了火箭筒,可以防空。
類圖:
代碼實現:
using System;namespace DecoratorPattern {/// <summary>/// MainApp startup class for Structural /// Observer Design Pattern./// </summary>class MainApp{static void Main(string[] args){// 定義新兵Soldier soldier = new Soldier();// 三種裝備RifleEquipment rifle = new RifleEquipment();MachineGunEquipment machineGun = new MachineGunEquipment();RocketGunEquipment rocketGun = new RocketGunEquipment();// 將三種裝備全部交給新兵 rifle.SetComponent(soldier);machineGun.SetComponent(rifle);rocketGun.SetComponent(machineGun);// 攻擊,除了拳腳功夫外,新兵還可以使用步槍,機槍,火箭炮.最終執行的是rocketGun.Attack(). rocketGun.Attack();Console.Read();}}/// <summary>/// 裝備類,相當于Component/// </summary>public abstract class Equipment{public abstract void Attack();}/// <summary>/// 士兵類,繼承自Equipment/// </summary>public class Soldier : Equipment{public Soldier(){// 構造函數 }/// <summary>/// 沒有任何武器裝備下的核心功能/// </summary>public override void Attack(){Console.WriteLine("用拳腳攻擊!");}}public abstract class EquipDecorator : Equipment{protected Equipment equipment;/// <summary>/// 增加裝備,使用該方法來動態地給士兵增加裝備/// </summary>/// <param name="equipment"></param>public void SetComponent(Equipment equipment){this.equipment = equipment;}/// <summary>/// 攻擊/// </summary>public override void Attack(){//如果有裝備,就用裝備進行攻擊if (equipment != null){equipment.Attack();}}}/// <summary>/// 步槍/// </summary>public class RifleEquipment : EquipDecorator{public override void Attack(){base.Attack();Console.WriteLine("步槍射擊,啪!");}}/// <summary>/// 機槍/// </summary>public class MachineGunEquipment : EquipDecorator{public override void Attack(){base.Attack();Console.WriteLine("機槍掃射,突突突!");}}/// <summary>/// 火箭筒/// </summary>public class RocketGunEquipment : EquipDecorator{public override void Attack(){base.Attack();Console.WriteLine("火箭炮射擊,唰......!");}} }輸出結果:
?
優點
1 每個裝飾對象只關心自己的功能,不需要關心如何被添加到對象鏈當中。它是由Decorator的SetComponent方法來實現的,因而它們的職責是單一的。
2 類的核心職責與動態添加的職責是分離的。如果再向主類中添加新的功能,一是違反了開放封閉原則,二是增加了主類的復雜度。
3?比靜態繼承更靈活?與對象的靜態繼承相比,Decorator模式提供了更加靈活的向對象添加職責的方式,可以使用添加和分離的方法,用裝飾在運行時刻增加和刪除職責.
缺點
1?產生許多小對象,采用Decorator模式進行系統設計往往會產生許多看上去類似的小對象,這些對象僅僅在他們相互連接的方式上有所不同。
適用場景
1 當需要為已有功能動態地添加更多功能時。
2 類的核心功能無需改變,只是需要添加新的功能時。
?
?
總結
以上是生活随笔為你收集整理的装饰模式【设计模式学习-03】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 旅行商问题(TSP) 中国34个城市 经
- 下一篇: asp.net ajax控件工具集 Au