走向.NET架构设计—第五章—业务层模式,原则,实践(中篇)
走向.NET架構設計—第五章—業(yè)務層模式,原則,實踐(中篇)
前言:設計模式并不是什么很高深的東西,至少不是那么“神乎其神”。說到底,設計模式就是一些設計思想。下面我們就走進項目,看看這些項目中這些思想是如何體現(xiàn)的。本系列文章會在后續(xù)文章中陸陸續(xù)續(xù)的,在恰當?shù)臅r候介紹一些相應的設計模式,而不是一股腦的一起上。?
本篇的議題如下:
架構模式
設計模式
設計原則
?
?
?
?
設計模式
本篇文章主要是討論的在業(yè)務層可以采用的或者常用的一些設計模式:
Factory Method
Decorator
Template Method
State
Strategy
?
Factory Method
相信很多朋友對這個模式很熟悉了,平時在項目中或多或少總能看到Factory, Provider等。確實Factory Method一種創(chuàng)建型的模式,它的主要目的就是隱藏對象創(chuàng)建的細節(jié)。也就是說,客戶程序(或者成為調用者)不用特定來什么創(chuàng)建某一種具體的類,也不依賴于特定的類,而且依賴接口或者抽象類,這樣就達到了解耦,專業(yè)點的說法就是“依賴倒置”,更加直白的說法就是:客戶程序可以使用很多不同的實現(xiàn)類,而保持代碼不變。因為在需要的時候,傳入一些信息,Factory Methods就返回接口或者抽象類的實現(xiàn)類。
?
???????? 很多情況下,我們一般是這樣來使用Factory Method模式的:建立一個Factory類,這個類有一個靜態(tài)的方法,這個方法返回一個抽象的類或者接口。然后,客戶程序(或者調用程序)就傳入一些信息給Factory類來,要求Factory來創(chuàng)建相對應,需要的具體的實現(xiàn)類。
?
???????? 下面我們就看看一個Factory Method的UML圖:
?
?
?
?? 在圖中,可以得出以下幾點信息:
q?Client類通過Factory類來獲取實現(xiàn)了IProduct的具體子類。
q?Client類依賴IProduct接口,而不是依賴具體的子類。
q?Factory類復雜創(chuàng)建具體的子類,向Client隱藏具體的細節(jié)。
?
??? 現(xiàn)在網(wǎng)上購物已經(jīng)很流行了,在選擇支付方式的時候,一般有幾種選擇,比如:網(wǎng)銀支付,貨到付款支付等。對于網(wǎng)銀支付,又可以進一步細分為:中國銀行支付、工商銀行支付等。不同的銀行支付,最后調用的接口都不一樣,而且以后系統(tǒng)可能會支持更多的銀行。所以在設計支付功能的時候需要考慮到擴展性。本例將會介紹如何采用工廠方法模式來實現(xiàn)支付功能。
?
? 請看下圖:
?
????????
下面我們就通過代碼來講述:(大家可以一起動手) ?
???? IPayment支付方式的接口代碼如下所示:
?
public?interface?IPayment{
??????bool?Payfor(decimal?money);
}
?
支付實現(xiàn)者ABCPayment支付類的代碼如下所示:
?
public?class?ABCPayment:IPayment??{
????????public?bool?Payfor(decimal?money)
????????{
???????????//調用中國農業(yè)銀行提供的支付接口進行支付
????????????return?true;
????????}
???}
?????? ICBCPayment、AOCPayment的實現(xiàn)同理。
?????? PaymentFactory的任務就是根據(jù)傳入的條件來創(chuàng)建不同的具體支付者:
?
public?class?PaymentFactory{
????????public?static?IPayment?CreatePayment(string?bank)
????????{
????????????IPayment?result?=?null;
????????????switch?(bank)
????????????{
????????????????case?"ABC":
????????????????????result?=?new?ABCPayment();
????????????????????break;
????????????????case?"ICBC":
????????????????????result?=?new?ICBCPayment();
????????????????????break;
????????????}
????????????return?result;
????????}
}
?
????? 當然,可以采用更好的方式來實現(xiàn)PaymentFactory的CreatePayment方法,例如采用配置文件,動態(tài)加載程序集的方式。
Decorator
??????? 為了更好地理解“裝飾”的概念,我們首先拋開枯燥的闡述,來看看現(xiàn)在流行的網(wǎng)游。在網(wǎng)游中玩家可以給自己的賬號購買不同的裝備,而且不同的裝備其特性也不一樣,比如重量、防御能力、攻擊能力等。下面就以裝備中的鎧甲為引子來講述“裝飾”。
?????? 下面,我們就看看如何實現(xiàn)鎧甲的升級功能:從最初的青銅甲一步步升級到麒麟甲。
?
??????? 其中:
Knight:代表武將。
IArmour:鎧甲接口。QTArmour為青銅鎧甲,BLGJArmour為百煉鋼甲,QLArmour為麒麟甲。
??????? 每次鎧甲升級,都是通過工廠武將創(chuàng)建新的鎧甲子類替換原來的鎧甲。
?
????????如果以后有新的鎧甲或要對現(xiàn)有的鎧甲功能進行增強,可以采用繼承的方式實現(xiàn)。例如現(xiàn)在麒麟鎧甲要增加隱形功能,本著“開放關閉原則”,最容易想到的就是添加一個新的子類,從QLArmour(青銅鎧甲)繼承現(xiàn)有的功能,同時再加上新的功能。如果再要新加上其他功能,其步驟也與此類似,原本就想通過繼承來重用現(xiàn)有的代碼,現(xiàn)在這個目的達到了,但是最后系統(tǒng)中存在了很多的功能相近的類,導致類的數(shù)目急劇膨脹。
???????如果能夠在現(xiàn)有鎧甲上面通過不斷的改造,增加新的功能,類似于變形金剛變身那樣,使加入了新功能的青銅甲鎧甲演變成麒麟甲,成為新類型的鎧甲,那么類的數(shù)目就不會像之前那樣膨脹了。?????
?????? 網(wǎng)游的例子到此暫告一個段落,主要就是想讓大家了解一下“裝飾”的含義,至于如何實現(xiàn),在講完下面的例子之后大家就清楚了。
要遵循“開放關閉”原則,同時又要規(guī)避使用繼承帶來的類膨脹問題,如何實現(xiàn)?裝飾者模式回答了這個問題。
?
?
??? 如圖,先不管圖中類名的定義,首先看看主要類的含義:
???????? (1) OnlineSitePriceDecorator代表購物站點的打折。
???????? (2) SupplierPriceDecorator代表供應商的打折。
???????? (3) PolicyPriceDecorator代表政府要求的打折。
?
??????在打折的時候,需要考慮:打折就是改變產(chǎn)品的價格,而很多時候,價格往往只是產(chǎn)品的一個屬性,例如,通常會采用decimal等數(shù)據(jù)類型。
????? 現(xiàn)在因為價格總是在不斷地根據(jù)打折算法的變換而變化,那么現(xiàn)在“價格”就成了一個變化點;另一方面,更加準確的說:打折算法是用在價格之上的,這樣才能實現(xiàn)對產(chǎn)品的打折。考慮把價格這個變化點引出去,成為一個業(yè)務實體Price,然后把打折算法都累積在這個實體上面進行,產(chǎn)品類Product絲毫不知道Price類是否應用了打折算法,只管引用Price獲取最后的價格。
?
public?interface?IPrice???{
????????decimal?Cost?{?get;?set;?}
???}
public?class?Product
????{
????????public?string?Name?{?get;?set;?}
????????public?IPrice?Price?{?get;?set;?}
????}
?
下面,開始添加不同打折算法的實現(xiàn)。
??? 首先我們來回想一下之前裝備升級的例子,我們是希望通過不斷地改造青銅甲,在原有的基礎上加上新的功能,最后達到裝備升級的目的。此時,在價格打折上面,因為同時要采用很多的打折算法,也類似于給價格不斷的“升級”:在原有的價格上不斷進行包裝。所以OnlineSitePriceDecorator購物網(wǎng)站推出的打折方法如下:
?
public?class?OnlineSitePriceDecorator?:?IPrice{
????????private?IPrice?price;
????????public?OnlineSitePriceDecorator(IPrice?price)
????????{
????????????this.price?=?price;
????????}
????????public?decimal?Cost
????????{
????????????get
????????????{
????????????????return?price.Cost?*?0.9M;
????????????}
????????????set
????????????{
????????????????price.Cost?=?value;
????????????}
????????}
}
?
??? 從上面的代碼中我們可以看出,拿到商品的原價后進行包裝:proce.Cost*0.9M。在經(jīng)過OnlineSitePriceDecorator包裝之后把價格拋出來,進行下一個包裝:供應商打折。供應商打折的代碼如下所示:
?
public?class?SupplierPriceDecorator?:?IPrice{
????????private?IPrice?price;
????????public?SupplierPriceDecorator(IPrice?price)
????????{
????????????this.price?=?price;
????????}
????????public?decimal?Cost
????????{
????????????get
????????????{
????????????????return?price.Cost?*?0.85M;
????????????}
????????????set
????????????{
????????????????price.Cost?=?value;
????????????}
????????}
}
?
下面看看如何實現(xiàn)累積打折算法,代碼如下:
?
public?class?ProductService{
????????private?IProductRepository?productRepository;
????????public?ProductService(IProductRepository?productRepository)
????????{
????????????this.productRepository?=?productRepository;
????????}
????????public?List<Product>?GetProducts()
????????{
????????????var?products?=?productRepository.GetAllProduct();
????????????products.ApplyDiscount();
????????????return?products;
????????}
}
//其中ApplyDiscount為List的擴展方法,如下所示:
public?static?class?DiscountExtension
{
????????public?static?List<Product>?ApplyDiscount(this?List<Product>?products)
????????{
????????????if?(products?!=?null?&&?products.Count?>?0)
????????????{
????????????????foreach?(var?product?in?products)
????????????????{
????????????????????product.Price?=?new?OnlineSitePriceDecorator(product.Price);
????????????????????product.Price?=?new?SupplierPriceDecorator(product.Price);
????????????????????product.Price?=?new?PolicyPriceDecorator(product.Price,?0.88M);
????????????????}
??????????}
????????????return?products;
????????}
?
價格包裝的過程如圖所示。
?
以上就是本篇的內容,講述的很粗略,希望見諒,還沒有寫完,待續(xù)!J
?
轉載于:https://www.cnblogs.com/yanyangtian/archive/2010/11/19/1881383.html
總結
以上是生活随笔為你收集整理的走向.NET架构设计—第五章—业务层模式,原则,实践(中篇)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TP-Link TL-WR2041N V
- 下一篇: 从MS .NET CF版访问电话API(