天天看點

Head.First.Object-Oriented.Design.and.Analysis《深入淺出面向對象的分析與設計》讀書筆記(四)...

  

  

 用真實世界檢驗你的軟體-分析
 引用

      是時候畢業了,時候去真實世界檢驗自己的軟體了。

      上個版本的狗門很是成功,賣的很瘋狂。但是越是賣的還要,抱怨就會越多。下面就是一個使用者的意見。

      “我非常喜歡你的系統,那個語音識别器。但是在我安裝了之後,每次鄰居家的狗叫的話,門也會自動打開。但是這不是我想要的效果。”

 正文

      你的軟體有了一個上下文。到目前為止,我們是在一個真空,沒有結合軟體運作環境的情況下開發軟體。換句話說,我們把軟體想象為:運作在完美的世界,在我們預期的情況下運作。每個人都很輕松,周圍沒有很多條狗。

      但是我們的軟體終究要運作在真實的世界,而不是一個完美的世界。在真實的世界中,可能會運作錯誤。周圍也會有很多的狗,貓之類的動物。

      使得你的軟體在真實世界不被搞糟的關鍵在于分析:在你把軟體放到真實世界之前,找出潛在的問題,并且解決這些問題。

      1、确定(識别)問題

      第一步是找到潛在的問題。我們已經知道,就是鄰居家有很多隻狗。

      使用遙控器沒有問題,因為是人工幹預。人是可以識别自己家的狗叫的。但是語音識别器好像就差了點,它一聽到狗叫就會打開門。意味着,任何一隻狗叫都可以打開門。

      2、設計一個解決方案

      使我們的use case出了問題,在識别器聽到狗叫之後沒有識别是否是自己家的狗,就打開了門。應該在聽到聲音之後,需要if判斷一下,然後再打開門。

      還需要識别器有存儲主人家的狗叫聲,才可以在收到狗叫之後進行比較。這時候,你就會發現,需要添加一個use case,就是存儲狗叫。用例比較簡單,就是:

      1)主人家的狗叫

      2)識别器存儲主人家的狗叫聲

      用例增加之後,就需要我們修改代碼。修改的方式有很多種,先看第一種:

      在DogDoor中添加一個string類型的字段,用來存儲叫聲;添加一個方法來設定叫聲;添加方法來擷取叫聲。

代碼 <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> using  System;

using  System.Collections.Generic;

using  System.Linq;

using  System.Text;

namespace  BeautyCode.Common.ConApp.Head.First.OO.Design

{

     public   class  DogDoor

    {

         private   bool  _open;

         private   string  _allowBark;

         public   void  SetAllowBark( string  bark)

        {

            _allowBark  =  bark;

        }

         public   string  GetAllowBark()

        {

             return  _allowBark;

        }

         public  DogDoor()

        {

            _open  =   false ;

        }

         public   void  Open()

        {

            Console.WriteLine( " the dog door opens " );

             this ._open  =   true ;

            System.Threading.Thread.Sleep( 5000 );

            Close();

        }

         public   void  Close()

        {

            Console.WriteLine( " the dog door closes " );

             this ._open  =   false ;

        }

         public   bool  IsOpen()

        {

             return  _open;

        }

    }

}

      另外一種做法就是比較面向對象的程式員寫的,建立一個類,定義叫聲類

代碼 <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> using  System;

using  System.Collections.Generic;

using  System.Linq;

using  System.Text;

namespace  BeautyCode.Common.ConApp.Head.First.OO.Design

{

     public   class  Bark

    {

         private   string  _sound;

         public  Bark( string  sound)

        {

            _sound  =  sound;

        }

         public   string  GetSound()

        {

             return  _sound;

        }

         public   override   bool  Equals( object  obj)

        {

             if  (obj  is  Bark)

            {

                Bark bark  =  obj  as  Bark;

                 if  (bark._sound.Equals( this ._sound))

                     return   true ;

                 else

                     return   false ;

            }

             return   false ;

        }

    }

}

      DogDoor類中的叫聲字段的類型則變成了建立的Bark類

代碼 <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> using  System;

using  System.Collections.Generic;

using  System.Linq;

using  System.Text;

namespace  BeautyCode.Common.ConApp.Head.First.OO.Design

{

      public   class  DogDoor2

    {

         private   bool  _open;

         private  Bark _allowBark;

         public   void  SetAllowBark(Bark bark)

        {

            _allowBark  =  bark;

        }

         public  Bark GetAllowBark()

        {

             return  _allowBark;

        }

         public  DogDoor2()

        {

            _open  =   false ;

        }

         public   void  Open()

        {

            Console.WriteLine( " the dog door opens " );

             this ._open  =   true ;

            System.Threading.Thread.Sleep( 5000 );

            Close();

        }

         public   void  Close()

        {

            Console.WriteLine( " the dog door closes " );

             this ._open  =   false ;

        }

         public   bool  IsOpen()

        {

             return  _open;

        }

    }

}

      相應的識别器類中的代碼就應該修改為

      識别器1

代碼 <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->    public   void  Recognize( string  bark)

        {

            Console.WriteLine( " Bark Recognizer: heard a  " + bark );

             if  (_door.GetAllowBark().Equals(bark))

                _door.Open();

             else

                Console.WriteLine( " this dog is not allow " );

        }

      識别器2

代碼 <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> -->   public   void  Recognize(Bark  bark)

        {

            Console.WriteLine( " Bark Recognizer: heard a  "   +  bark);

             if  (_door2.GetAllowBark().Equals(bark))

                _door.Open();

             else

                Console.WriteLine( " this dog is not allow " );

        }

      識别器2明顯好于識别器1,因為在2中将聲音比較的任務委托給了bark類來處理,識别器本身不處理,隻是根據處理的結果來做出決定。這樣就松散了耦合,解耦了識别器類和叫聲類。因為其他叫聲也很容可以添加進來,否則每一種叫聲都必須配備專用的識别器了。

      在分析的時候,需要注意需求或者是用例中的名詞和動詞。名稱經常會需要轉換成類,或者是類的一個屬性。動詞則經常會是一個方法。

      繼續上面的分析。

      狗一般不是叫一聲,有可能要叫很多聲,隻要一個聲音比對成功,就應該打開門。識别器需要存儲多個狗叫聲。

代碼 <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> using  System;

using  System.Collections.Generic;

using  System.Linq;

using  System.Text;

namespace  BeautyCode.Common.ConApp.Head.First.OO.Design

{

     public   class  DogDoor3

    {

         private   bool  _open;

         private  List < Bark >  _allowBark;

         public   void  SetAllowBark(Bark bark)

        {

            _allowBark.Add( bark);

        }

         public  List < Bark >  GetAllowBark()

        {

             return  _allowBark;

        }

         public  DogDoor3()

        {

            _open  =   false ;

        }

         public   void  Open()

        {

            Console.WriteLine( " the dog door opens " );

             this ._open  =   true ;

            System.Threading.Thread.Sleep( 5000 );

            Close();

        }

         public   void  Close()

        {

            Console.WriteLine( " the dog door closes " );

             this ._open  =   false ;

        }

         public   bool  IsOpen()

        {

             return  _open;

        }

    }

}

       這時候識别器就需要修改一下了

代碼 <!--<br/ /> <br/ /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ /> http://www.CodeHighlighter.com/<br/ /> <br/ /> --> using  System;

using  System.Collections.Generic;

using  System.Linq;

using  System.Text;

namespace  BeautyCode.Common.ConApp.Head.First.OO.Design

{

     public   class  BarkRecognizer

    {

         private  DogDoor3 _door3;

         public  BarkRecognizer(DogDoor3 door)

        {

            _door3  =  door;

        }

         public   void  Recognize3(Bark bark)

        {

            Console.WriteLine( " Bark Recognizer: heard a  "   +  bark);

             foreach  (Bark b  in  _door3.GetAllowBark())

            {

                 if  (b.Equals(bark))

                {

                    _door.Open();

                     return ;

                }

            }

            Console.WriteLine( " this dog is not allow " );

        }

    }

}

  結論

      要注意requirements和use case中的名詞,它們通常就是一個類或者是類中的一個屬性;其中的動詞通常會是一個類的方法。

繼續閱讀