用真實世界檢驗你的軟體-分析 |
引用 |
是時候畢業了,時候去真實世界檢驗自己的軟體了。
上個版本的狗門很是成功,賣的很瘋狂。但是越是賣的還要,抱怨就會越多。下面就是一個使用者的意見。
“我非常喜歡你的系統,那個語音識别器。但是在我安裝了之後,每次鄰居家的狗叫的話,門也會自動打開。但是這不是我想要的效果。”
正文 |
你的軟體有了一個上下文。到目前為止,我們是在一個真空,沒有結合軟體運作環境的情況下開發軟體。換句話說,我們把軟體想象為:運作在完美的世界,在我們預期的情況下運作。每個人都很輕松,周圍沒有很多條狗。
但是我們的軟體終究要運作在真實的世界,而不是一個完美的世界。在真實的世界中,可能會運作錯誤。周圍也會有很多的狗,貓之類的動物。
使得你的軟體在真實世界不被搞糟的關鍵在于分析:在你把軟體放到真實世界之前,找出潛在的問題,并且解決這些問題。
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中的名詞,它們通常就是一個類或者是類中的一個屬性;其中的動詞通常會是一個類的方法。