[設計模式] Strategy Pattern(策略模式) Part 2

Strategy Pattern(策略模式) Part 1裡面我們提到,如果我們裡用繼承父類別的方法,就會造成子類別被強迫實作他不需要的方法,有沒有更好的方式呢?

我們觀察到,每個角色共同擁有的功能是【攻擊】,只是攻擊的武器不同,因此,我們可以把攻擊這個方法獨立抽出來。先建立一個叫做Attack的Interface:


public interface Attack
{
    void useWeapon();
}


接著我們針對三個武器建立三個Class,分別是KnifeBehavior、SwordBehavior和AxeBehavior,同時這三個類別要去實作Attack這個介面:


public class KnifeBehavior implements Attack
{
     public void useWeapon()
     {
          System.out.println("Attack by Knife");
     }
}



public class SwordBehavior implements Attack
{
     public void useWeapon()
     {
          System.out.println("Attack by Sword");
     }
}



public class AxeBehavior implements Attack
{
     public void useWeapon()
     {
          System.out.println("Attack by Axe");
     }
}


接著,我們可以在原來角色的類別(Character)中,增加一個 setFightAction(Attack attack);的方法,這個方法可以讓實作他的角色類別依照需要來動態的產生不同的攻擊方法,因此,我們原本的角色類別變成:

public abstract class Character {
    public abstract void fight();
    public abstract void action();
    public abstract void char();
    public abstract void setFightAction(Attack attack);
}

如此一來,實作角色類別的個別角色(King、Queen和Knight)的程式就會變成:

public class King extends Character {

     Attack attack;

     @Override
     public void action() {}

     @Override
     public void chat() {}

     @Override
     public void fight() {
          f.useWeapon();
     }

     @Override
     public void setFightAction(Attack attack) {
          this.attack = attack;
     }
}


最後,我們要使用每個角色時,只需要這樣寫:

public class PlayGame {
    public static void main(String [] a) {
        King kevingo = new King();
        kevingo.setFightAction(new KnifeBehavior());
        kevingo.fight();

        Queen mary = new Queen();
        mary.setFightAction(new SwordBehavior());
        mary.fight();

        Knight tom = new Knight();
        tom.setFightAction(new KnifeBehavior());
        tom.fight();
    }
}


往後,當我們需要有新的攻擊方式時,只需要重新建立一個新的攻擊類別,而如果皇后要改拿其他的武器時,也只要在setFightAction中指定新的攻擊類別,真是太好了!

再回顧一下Strategy Pattern的定義:

  • 策略模式在於觀察程式中變動的部分,並且將他們抽離出來封裝成可互相抽換的演算法家族。這個模式讓你即使任意更換實作的演算法,也不會變動到去使用者他們的客戶端程式。

在這個範例中,我們把不同型態的攻擊方法抽出來變成一組家族,建立一個Interface叫做Attack,同時根據不同的攻擊方法來建立不同的類別,往後我們只要利用set方法就可以輕鬆的替換攻擊的方式,這就是策略模式的用途所在。

當然這個模式不是沒有缺點,最顯而易見缺點就是他必須要維護比較多的類別,當實作的策略變多的時候,維護起來就會比較吃力囉。

不喜歡Facebook新的瀏覽照片方式?試試看Better Facebook的外掛(支援Firefox、Chrome、Safari等多款瀏覽器)!


相信最近大家在用Facebook的時候,一定會發現瀏覽照片的方式變更了。現在Facebook會在前景開啟一個黑色為底的畫面來讓你瀏覽照片,不得不說這樣的瀏覽介面和方式實在有點難用加不美觀。今天介紹大家一個瀏覽器的外掛套件 -【Better Facebook】,可以讓你回覆到舊有瀏覽照片的方法,同時還增加了許多新功能,最棒的是這個外掛套件同持支援Firefox、Chrome、Safari、Opera等多款主流的瀏覽器,真是太棒了!


根據你使用的瀏覽器下載完成之後,第一次登入到Facebook頁面時會跑出設定的精靈選項,基本上可以直接一直按Next到底,因為事後都可以修改:


當中可以看到Better Facebook提供了類似分頁標籤的功能,可以針對不同的應用程式或朋友進行分類:


不過安裝Better Facebook最重要的還是要把照片瀏覽的方式改回原本自己習慣的瀏覽介面,很簡單,在Facebook的首頁的右上角會看到一個Options,點選進去就會跑出Better Facebook的設定畫面:


接著在【Popular】的標籤裡面,把【Disable the "Light Box".....】的選項給勾選起來,接著重新整理頁面,你會發現瀏覽照片的方法已經改回原本的囉!


而Better Facebook還有許多的功能,大家可以慢慢嘗試,當然如果不喜歡的話,就通通取消勾選只保留回復原本瀏覽照片的選項也是一招,大家試試看囉:)

在Visual Studio找不到DLL Reference?先確定Target Framework吧!

最近在練習C#程式開發時,偶而會碰到要reference某個dll的時候,找不到相對應的namespace,後來上網尋找了一下,發現不是這顆DLL消失了,而是Project裡面的Target Framework被設定為Client Profile的形式。


至於Client Profile和一般的.NET Framework有什麼不同,可以參考msdn上面的這篇文章:

.NET Framework Client Profile

另外這一篇文章也寫得不錯:

What’s new in .NET Framework 4 Client Profile RTM

簡而言之,Client Profile算是一個Compact Version,如果你要開發Web Service,也許可以用,但如果是桌面端AP的話,建議還是用原本的.NET Framework,比較可以省掉一些麻煩囉。

NUnit Test 筆記 (1) - NUnit in Visual Studio

NUnit是一個Open Source的框架,用來進行.NET程式的單元測試。以下分享一下自己閱讀以及使用NUnit的紀錄,希望對大家有些幫助。

什麼是單元測試(Unit Test)?


簡單來說,一個單元就是在程式當中最基本、最小的一個單位,最常見的是一個方法。單元測試就是為了去檢驗這個單元所執行的結果是否正確,換句話說,也就是去檢查程式的結果和程式設計師的預期規劃是否相同。

Unit testing is a method by which individual units of source code are tested to determine if they are fit for use. A unit is the smallest testable part of an application. In procedural programming a unit may be an individual function or procedure. Unit tests are created by programmers or occasionally by white box testers.
Ref: http://en.wikipedia.org/wiki/Unit_testing

下載NUnit並且在Visual Studio專案中引入DLL


NUnit 下載連結:http://www.nunit.org/index.php?p=download

如果是要在Visual Studio裡面使用的話,建議可以下載bin的連結,這樣就不用自己重新compile了。
下載回來之後,如果想要在Visual Studio裡面撰寫測試程式,必須要引用nunit.framework這個dll,把他加到你的專案裡面:


實際撰寫NUnit測試程式碼


假設我們有一個計算機(Calculator)的程式,測試時是想要去檢查內部的方法是否正確。首先可以建立兩個Project,一個是放計算機的主程式(這裡的namespace是kevingo.Calculator),另外一個Project則是撰寫測試程式碼用(NUnitTestProject)。

首先建立一個計算機的程式:


public class Calculator
{
    int result = 0;
    public int Add(int a, int b)
    {
        result = a+b;
        return result;
    }

    public int Sub(int a, int b)
    {
        result = a-b;
        return result;
     }

    public int Multiple(int a, int b)
    {
        result = a*b;
        return result;
    }

  
    public int Divide(int a, int b)
    {
        result = a/b;
        return result;
    }
}


在另外一個Project寫測試程式碼,這裡我偷懶一下,只先撰寫兩個測試方法來檢查Add和Sub的功能:

namespace NUnitTestProject
{
    [TestFixture]
    public class Program
    {
        Calculator c1 = new Calculator();

        [Test]
        public void TestAdd()
        {
            int addResult = c1.Add(10, 10);
            Assert.AreEqual(20, addResult);
         }

        [Test]
        public void TestSub()
        {
            int subResult = c1.Sub(10, 2);
            Assert.AreEqual(8, subResult);
        }
}


在撰寫測試程式碼的時候,記得先把Calculator這個Project Build成DLL引入到測試的Project中:




 執行NUnit測試結果


接著我們實際執行測試的結果,nunit提供了GUI介面,讓使用者可以很方便的檢驗測試的結果,為了方便測試,在build測試程式碼的時候,可以設定啟動nunit的GUI:




在Compile的時候應該就會把NUnit的GUI給帶出來,接著選擇File中的Open Project,把build出來的DLL(這裡叫做NUnitTestProject.dll)給開啟執行就可以看到結果,如果你的測試程式是正確的,就會顯示綠色,如果有錯的話就是紅色的結果,像這裡代表TestAdd是正確而TestSub是有問題的,如此一來就可以針對錯誤來修正:


第一篇先紀錄到這裡,下一篇來看看NUnit裡面有什麼Attributes可以用。