[讀書心得]深入淺出物件導向分析與設計-良好程式設計基石 OOAD Code設計範例介紹-2

在上一篇最後提到的,應用基本的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






image
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圖如下
image 

這邊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