2013年5月11日 星期六

一秒看破 裝飾者模式 Decorator Pattern

設計模式 (design patterns) 有人覺得很難 有人覺得很神秘

其實他是一種 在特定情境下 使用一些別具巧思的物件導向技巧 的方法

往往直接看定義說明 根本難以理解到底在幹嘛

那不如直接回歸原點 一開始就從[情境]來看看怎麼玩





這回要來玩弄的是 裝飾者模式 (Decorator Pattern)

先拜讀神人文

神人文 其實已經說明得很清楚了 小弟我也不必在此 裝很懂

我的心得是:

當有一群 [本質相近]但又個有些[不盡相同]的東西 的時候 適合使用 裝飾者模式





那就來玩一下吧 我們這麼宅 又覺得 不吃早餐才是一件很嘻哈的事

所以神人舉例的早餐 改成我們熟悉的東東





弄個 武器 抽象類 跟 一些武器


    //武器 抽象類
    public abstract class Weapon
    {
        public string Name = "砂鍋大的鐵拳";

        public virtual string GetName()
        {
            return Name;
        }

        public abstract double AttackPower();
    }

    //
    public class Sword : Weapon
    {
        public Sword()
        {
            base.Name = "";
        }

        public override double AttackPower()
        {
            return 10;
        }
    }

    //
    public class Knife : Weapon
    {
        public Knife()
        {
            base.Name = "";
        }

        public override double AttackPower()
        {
            return 5;
        }
    }




再弄個 強化武器 抽象裝飾者類 跟 一些強化功能


    //強化武器 抽象裝飾者類
    public abstract class StrengthenDecorator : Weapon
    {
        public abstract override double AttackPower();
    }

    //加長
    public class Long : StrengthenDecorator
    {
        private Weapon _weapon;

        public Long(Weapon weapon)
        {
            _weapon = weapon;
        }

        public override double AttackPower()
        {
            return _weapon.AttackPower() + 5;
        }

        public override string GetName()
        {
            return "加長的" + _weapon.GetName();
        }
    }

    //鋒利
    public class Sharp : StrengthenDecorator
    {
        private Weapon _weapon;

        public Sharp(Weapon weapon)
        {
            _weapon = weapon;
        }

        public override double AttackPower()
        {
            return _weapon.AttackPower() + 20;
        }

        public override string GetName()
        {
            return "鋒利的" + _weapon.GetName();
        }
    }

    //劇毒
    public class Toxic : StrengthenDecorator
    {
        private Weapon _weapon;

        public Toxic(Weapon weapon)
        {
            _weapon = weapon;
        }

        public override double AttackPower()
        {
            return _weapon.AttackPower() + 100;
        }

        public override string GetName()
        {
            return "劇毒的" + _weapon.GetName();
        }
    }

    //傳說
    public class Legendary : StrengthenDecorator
    {
        private Weapon _weapon;

        public Legendary(Weapon weapon)
        {
            _weapon = weapon;
        }

        public override double AttackPower()
        {
            return _weapon.AttackPower() + 9999;
        }

        public override string GetName()
        {
            return "傳說的" + _weapon.GetName();
        }
    }




最後 拉些 可有可無的 UI 看看效果



    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private Weapon weapon;

        private void Sword_rb_CheckedChanged(object sender, System.EventArgs e)
        {
            weapon = new Sword();
            Log(weapon.GetName(), weapon.AttackPower());
            Knife_rb.Enabled = Sword_rb.Enabled = false;
        }

        private void Knife_rb_CheckedChanged(object sender, System.EventArgs e)
        {
            weapon = new Knife();
            Log(weapon.GetName(), weapon.AttackPower());
            Knife_rb.Enabled = Sword_rb.Enabled = false;
        }

        private void GetLong_Click(object sender, System.EventArgs e)
        {
            weapon = new Long(weapon);
            Log(weapon.GetName(), weapon.AttackPower());
        }

        private void GetSharp_Click(object sender, System.EventArgs e)
        {
            weapon = new Sharp(weapon);
            Log(weapon.GetName(), weapon.AttackPower());
        }

        private void GetToxic_Click(object sender, System.EventArgs e)
        {
            weapon = new Toxic(weapon);
            Log(weapon.GetName(), weapon.AttackPower());
        }

        private void GetLegendary_Click(object sender, System.EventArgs e)
        {
            weapon = new Legendary(weapon);
            Log(weapon.GetName(), weapon.AttackPower());
        }

        private void Log(string name, double attackPower)
        {
            Log_lb.Text +=
                "勇者OO拾取了 [" + name + "]" +
                "攻擊力:" + attackPower + "" +
                Environment.NewLine;
        }
    }





定番截圖

12 則留言:

  1. 這個舉例比早餐的 case 合理多了!

    回覆刪除
  2. sorry for one question
    If we can do this with only one List < StrengthenDecorator > (use the same type as your example)
    and override the Get_*() to something like this
    power = 10 <-- base obj
    for (all obj)
    power += obj <-- each append obj
    return power

    and we can have the same result, isn't it ?
    By using Decorate Pattern, we have to create a lot of Classes, but I really cannot tell what good of using Decorate

    回覆刪除
    回覆
    1. BTW, this is a better example indeed!

      刪除
  3. Yes, you're right. Decorator Pattern creates a lot of Classes, and there are some ways can get an exactly same result like you say.
    Here are some timings I think we can use Decorator Pattern
    1. A project already used Decorator Pattern, so you have no choices. (lol. I'm joking, but it could be real a situation.)
    2. Sometimes, you wouldn't want to do the similar things when you override methods.
    In this example, I just append Name and AttackPower.
    If you want to deal with many dissimilar features, you might use a lot of "if" or "switch".
    When your features are more complex, your code will become dirty.
    On the other hand, using Decorator Pattern can encapsulate each feature in each Classe.
    You can make sure that you edit this class won't damage other Classes(In theory), and you will have better readability

    To be honest, I didn't use Decorator Pattern in any projects because I haven't face such complex features.
    This is just for learning design pattern :)

    回覆刪除
    回覆
    1. Thank you for answering kindly.
      It seems #1 might be more likely to happen.
      Let's see if there is any chance to use this =)

      刪除
  4. 厲害了
    不知道為啥我一看到遊戲例子我就看得很入迷...很認真....

    回覆刪除
  5. 感謝您的例子, 好文讚啦:)

    回覆刪除
  6. 竟然有這種可以看到讓嘴角一直不爭氣地往上翹,又保有高度專業水準的程式設計文.
    讚!
    神人文的內容也很讓人好奇,可惜神人文連結已經失效:(
    http://www.dotblogs.com.tw/pin0513/archive/2010/01/04/12779.aspx

    回覆刪除
    回覆
    1. 點部落有改版,現在的網址是這一個
      https://www.dotblogs.com.tw/pin0513/2010/01/04/12779

      刪除