在上一篇最後提到的,應用基本的OO原則,增加軟體彈性,這篇文章就介紹關於第二個範例
將介紹如何分離出本身物件的屬性,與真正物件本身分開,
將分離出的屬性透過封裝的方式,來讓查詢的合理性增加。
在上一篇最後提到的,應用基本的OO原則,增加軟體彈性,這篇文章就介紹關於第二個範例,
上一個範例中,已經可以達成查詢到所輸入的Guitar規格,再來是我們來建立比較合理的步驟,
首先再查詢程式輸入的地方,我們是建立了一個Guitar的物件,傳入 Inventory 的 search()
但只會輸入是吉他的特性,並不會輸入到價格或序號(針對此次的查詢)
Guitar whatErinLikes = new Guitar("", 0, "fender", "Stratocastor",
"electric", "Alder", "Alder");
所以我們分析search()他因該要做的事情是
1.客戶提供吉他的喜好特性
2.搜尋庫存
3.比較每一個吉他與客戶喜好特性相比
4.傳回符合的清單
首先我們先改善search(),不是將一整個 Guitar 物件傳入,而是傳入一個喜好的特性,
但不因此再多做一個跟Guitar物件一樣的物件出來,而是我們將本來的規格封裝(encapsulate)
到一個新的物件,而這個物件是Guitar物件下的規格。
我們先將本來的規格屬性再從本來的Guitar 轉到 GuitarSpec
由下物件圖可以看出我們將規格欄位轉移到GuitarSpec
Guitar.cs
public class Guitar
{
private String serialNumber, builder, model, type, backWood, topWood;
private double price;
GuitarSpec spec;
public Guitar(String serialNumber, double price,
Builder builder, String model, Type type,
Wood backWood, Wood topWood)
{
this.serialNumber = serialNumber;
this.price = price;
//將屬性加入GuitarSpec內
this.spec = new GuitarSpec(builder, model, type, backWood, topWood);
}
public String getSerialNumber()
{
return serialNumber;
}
public double getPrice()
{
return price;
}
public void setPrice(float newPrice)
{
this.price = newPrice;
}
public GuitarSpec getSpec()
{
return spec;
}
}
GuitarSpec.cs
public class GuitarSpec
{
private Builder builder;
private String model;
private Type type;
private Wood backWood;
private Wood topWood;
public GuitarSpec(Builder builder, String model, Type type,
Wood backWood, Wood topWood)
{
this.builder = builder;
this.model = model;
this.type = type;
this.backWood = backWood;
this.topWood = topWood;
}
public Builder getBuilder()
{
return builder;
}
public String getModel()
{
return model;
}
public Type getType()
{
return type;
}
public Wood getBackWood()
{
return backWood;
}
public Wood getTopWood()
{
return topWood;
}
}
完成修改後Class圖如下
這邊Dotjum做各小註釋一下,為什麼要那麼麻煩要處理這個封裝呢?
在之後的範例,我們會針對屬性再多增加一個,但時你就可以觀察到
當封裝起來時,對其他程式要做的修改及影響的降低。
當完成將原本 Guitar 的 Spec 移至 GuitarSpec 後,
我們將Inventroy.cs 的 search() 改完傳入 GuitarSpec (其餘不變)
public class Inventory
{
private List<Guitar> guitars;
public Inventory()
{
guitars = new List<Guitar>();
}
public void addGuitar(String serialNumber, double price,
Builder builder, String model,
Type type, Wood backWood, Wood topWood)
{
Guitar guitar = new Guitar(serialNumber, price, builder,
model, type, backWood, topWood);
guitars.Add(guitar);
}
public Guitar getGuitar(String serialNumber)
{
foreach(Guitar guitar in guitars)
{
if (guitar.getSerialNumber().Equals(serialNumber))
{
return guitar;
}
}
return null;
}
//傳入是GuitarSpec 而不是傳入一個Guitar
public List<Guitar> search(GuitarSpec searchSpec)
{
List<Guitar> matchingGuitars = new List<Guitar>();
foreach (Guitar guitar in guitars)
{
//改以GuitarSpec比對
GuitarSpec guitarSpec = guitar.getSpec();
if (searchSpec.getBuilder() != guitarSpec.getBuilder())
continue;
String model = searchSpec.getModel().ToLower();
if ((model != null) && (!model.Equals("")) &&
(!model.Equals(guitarSpec.getModel().ToLower())))
continue;
if (searchSpec.getType() != guitarSpec.getType())
continue;
if (searchSpec.getBackWood() != guitarSpec.getBackWood())
continue;
if (searchSpec.getTopWood() != guitarSpec.getTopWood())
continue;
matchingGuitars.Add(guitar);
}
//既使比對條件改變但回傳還是回傳Guitar清單
return matchingGuitars;
}
}
所以我們在頁面這邊使用search的時候,則是傳入GuitarSpec方式
GuitarSpec whatErinLikes = new GuitarSpec(Builder.FENDER, "Stratocastor",
Type.ELECTRIC, Wood.ALDER, Wood.ALDER);
//這一次是傳入GuitarSpec給Search
List<Guitar> matchingGuitars = inventory.search(whatErinLikes);
if (matchingGuitars.Count > 0)
{
Response.Write("Erin, you might like these guitars:</BR> ");
foreach (Guitar guitar in matchingGuitars)
{
//取的該Guitar下的GuitarSpec
GuitarSpec spec = guitar.getSpec();
Response.Write(" We have a " +
spec.getBuilder() + " " + spec.getModel() + " " +
spec.getType() + " guitar:</BR> " +
spec.getBackWood() + " back and sides,</BR> " +
spec.getTopWood() + " top.</BR> You can have it for only $" +
guitar.getPrice() + "!</BR> " + guitar.getSerialNumber() + "----");
}
}
else
{
Response.Write("Sorry, Erin, we have nothing for you.");
}
透過第一個步驟,將吉他本身的特性,封裝到另一各類別,Dotjum已經完成,
到這一步,Dotjum可以先比較清楚將封裝先建立起來,但好處是什麼呢?
我們在下一個範例來延伸這個概念 3.達成可維護、可重利用的設計。
本篇文章程式碼及概念取用 深入淺出物件導向分析與設計
(若觀念等相關錯誤有錯誤,請務必告訴Dotjum)
相關文章:[讀書心得]深入淺出物件導向分析與設計-良好程式設計基石 OOAD Code設計範例介紹-1