C#使用設計模式和軟體設計原則構建應用程式 PartIII

來源:互聯網
上載者:User

標籤:style   blog   color   使用   os   io   for   ar   

依賴注入

這個原則的要點是什麼。為什麼你不能對類的執行個體進行再次寫入程式碼?當我們編碼,測試的時候,讓我們關注一件很重要的事情。希望你知道單元測試並知道它的重要性。也許在你做任何編碼之前你都應該首先設計你的測試,因此你應該很熟悉測試驅動開發。為了定義新功能你應該去寫測試,你應該嘗試去實現並開始編碼直到測試通過。讓我們先看看之前的文章的代碼。

public class DateBasedTaxFactory:ITaxFactory    {        Customer _customer;        ITaxFactory _taxFactory;        public DateBasedTaxFactory(Customer c, ITaxFactory cb)        {            _customer = c;            _taxFactory = cb;        }        public ITax GetTaxObject()        {            if (_customer.StateCode == "TX"                && DateTime.Now.Month == 4                && DateTime.Now.Day == 4)                return new NoTax();            else                return _taxFactory.GetTaxObject();        }    }

我們有DateBasedTaxFactory,當我們應該測試一下這個工廠是否能夠正常的工作。 是否每年的4月4日這個Tax類型的傳回值都應該是0.我們也許會建立一個如下的測試。

Customer cust = new Customer(){StateCode = "TX", County = "Travis", ZipCode = "78745"};    DateBasedTaxFactory db = new DateBasedTaxFactory(cust, new CustomerBasedTaxFactory(cust));    ITax tax = db.GetTaxObject();    //test for no tax for a certain date    if(tax.CalculateTax(3m) != 0)    {        throw new Exception("the value is supposed to be zero");    }

這裡有什麼問題嗎?我們不能真正的測試這個!正如你可以在DateBasedTaxFactory中看到的,為了測試當前的日期,它直接使用DateTime對象的Now屬性。除非你改變你系統的時間不然我們不能使得NoTax的條件滿足。更改系統時間是不理想的。我們還能做其他的事情嗎?有時這個工廠類有個引用一個隱藏的屬性,它是寫入程式碼實現的,它依賴一些需要變化的東西。工廠類需要一個DateTime對象。它不需要DateTime是當前的日期。它不關注給它的日期是什麼。為了告訴外面的世界這個類需要什麼來工作我們需要使用依賴注入。這將允許我們的測試給他任何需要測試的日期。就如下面所示:

public class DateBasedTaxFactory : ITaxFactory{    Customer _customer;    ITaxFactory _taxFactory;    DateTime _dt;    public DateBasedTaxFactory(Customer c, ITaxFactory cb,DateTime dt)    {        _customer = c;        _taxFactory = cb;        _dt = dt;    }    public ITax GetTaxObject()    {        if (_customer.StateCode == "TX" && _dt.Month == 4 && _dt.Day == 4)        {            return new NoTax();        }        else            return _taxFactory.GetTaxObject();    }} 

現在我們可以調整我們的測試來發送任何我們想要測試的日期。

Customer cust = new Customer(){StateCode = "TX",County ="Travis",ZipCode = "78745"};DateBasedTaxFactory db = new DateBasedTaxFactory(cust, new CustomerBasedTaxFactory(cust),    new DateTime(2001,4,4));ITax tax = GetTaxObject();//test for no tax for a certain dateif (tax.CalculateTax(3m) != 0){    throw new Exception("the value is supposed to be zero");}

單一原則/開閉原則

為什麼你的對象應該只做一件事情?為什麼你應該從不改變他們?顯示生活變化了那麼為什麼代表生活變化的代碼不能變化?讓我們看看之前的穩重中的第一個版本的Order類。好的,假如說你的公司有一個堅定的政策,在您的系統中的主要程式集BusinessLogic.dll每兩個月只有一個發布版本。假如有個bug或者在這之前需要做些變更,這將是一項繁瑣艱巨的任務。但是我們可以用較少的麻煩來定義一個可補充的發布程式集。如果我們使用如下原始碼:

public class Order{    List<OrderItem> _orderItems = new List<OrderItem>();    public decimal CalculateTotal(Customer customer)    {        decimal total = _orderItems.Sum((item)=>{            return item.Cost * item.Quantity;        });        decimal tax;        if (customer.StateCode == "TX")            tax = total * .08m;        else if (customer.StateCode == "FL")            tax = total * .09m;        else            tax = .03m;        total = total + tax;        return total;    }}

如果在TX的稅費邏輯發生了變化或者需要一個新的State的稅費,我們將必須要去修改Order對象。這將會造成 很大的臭味,因為我們需要去測試並發布BusinessLogic.dll.由於它有稅費有關,如果事情發生了很大的變化並且他將要投入生產ASAP中是,法律和金錢是一個不錯的選擇。

從其他的文章中我們已經做了我們需要做的事情,例如:

 public interface ITax    {        decimal CalculateTax(decimal total);    }    public class TXTax:ITax    {        public decimal CalculateTax(decimal total)        {            return total * 0.08m;        }    }    public class CustomerBasedTaxFactory:ITaxFactory    {        Customer _customer;        static Dictionary<string, ITax> stateTaxObjects = new Dictionary<string, ITax>();        static Dictionary<string, ITax> countyTaxObjects = new Dictionary<string, ITax>();        public CustomerBasedTaxFactory(Customer customer)        {            _customer = customer;        }        public ITax GetTaxObject()        {            ITax tax;            if(!string.IsNullOrEmpty(_customer.County))            {                if (!countyTaxObjects.Keys.Contains(_customer.StateCode))                {                    tax = (ITax)Activator.CreateInstance("Tax", "Solid.taxes." + _customer.County + "CountyTax");                    countyTaxObjects.Add(_customer.StateCode, tax);                }                else                    tax = countyTaxObjects[_customer.StateCode];            }            else            {                if (!stateTaxObjects.Keys.Contains(_customer.StateCode))                {                    tax = (ITax)Activator.CreateInstance("Tax", "Solid.taxes." + _customer.StateCode + "Tax");                    stateTaxObjects.Add(_customer.StateCode, tax);                }                else                    tax = stateTaxObjects[_customer.StateCode];            }            return tax;        }    }

我們有我們的TaxFactory來建立Tax對象並且所有的Tax邏輯都是在它的單獨類中來完成的。因此到現在為止ITax類可以被引入到其他的程式集當中來做一些Tax相關的任務。Tax.dll。如果發生了變化,那麼只需要在當前的程式集當中測試,並且它的附加程式集也不會有太多繁文縟節的事情。

好了,就這樣吧,下次再見。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.