译C#使用设计模式和软件设计原则构建应用程序 PartIII
依賴注入
這個原則的要點是什么。為什么你不能對類的實例進行再次硬編碼?當我們編碼,測試的時候,讓我們關注一件很重要的事情。希望你知道單元測試并知道它的重要性。也許在你做任何編碼之前你都應該首先設計你的測試,因此你應該很熟悉測試驅動開發。為了定義新功能你應該去寫測試,你應該嘗試去實現并開始編碼直到測試通過。讓我們先看看之前的文章的代碼。
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();elsereturn _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 dateif(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();}elsereturn _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 date if (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;elsetax = .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);}elsetax = 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);}elsetax = stateTaxObjects[_customer.StateCode];}return tax;}}我們有我們的TaxFactory來創建Tax對象并且所有的Tax邏輯都是在它的單獨類中來完成的。因此到現在為止ITax類可以被引入到其他的程序集當中來做一些Tax相關的任務。Tax.dll。如果發生了變化,那么只需要在當前的程序集當中測試,并且它的附加程序集也不會有太多繁文縟節的事情。
好了,就這樣吧,下次再見。
轉載于:https://www.cnblogs.com/szkk/p/3917003.html
總結
以上是生活随笔為你收集整理的译C#使用设计模式和软件设计原则构建应用程序 PartIII的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 树莓派学习笔记 1 -- 硬件的需求以及
- 下一篇: HTTPD(三)--HTTP2.4.9编