走向.NET架構設計—第五章—業務層模式,原則,實踐(中篇)
前言:設計模式并不是什麼很高深的東西,至少不是那麼“神乎其神”。說到底,設計模式就是一些設計思想。下面我們就走進項目,看看這些項目中這些思想是如何展現的。本系列文章會在後續文章中陸陸續續的,在恰當的時候介紹一些相應的設計模式,而不是一股腦的一起上。
本篇的議題如下:
架構模式
設計模式
設計原則
設計模式
本篇文章主要是讨論的在業務層可以采用的或者常用的一些設計模式:
Factory Method
Decorator
Template Method
State
Strategy
Factory Method
相信很多朋友對這個模式很熟悉了,平時在項目中或多或少總能看到Factory, Provider等。确實Factory Method一種建立型的模式,它的主要目的就是隐藏對象建立的細節。也就是說,客戶程式(或者成為調用者)不用特定來什麼建立某一種具體的類,也不依賴于特定的類,而且依賴接口或者抽象類,這樣就達到了解耦,專業點的說法就是“依賴倒置”,更加直白的說法就是:客戶程式可以使用很多不同的實作類,而保持代碼不變。因為在需要的時候,傳入一些資訊,Factory Methods就傳回接口或者抽象類的實作類。
很多情況下,我們一般是這樣來使用Factory Method模式的:建立一個Factory類,這個類有一個靜态的方法,這個方法傳回一個抽象的類或者接口。然後,客戶程式(或者調用程式)就傳入一些資訊給Factory類來,要求Factory來建立相對應,需要的具體的實作類。
下面我們就看看一個Factory Method的UML圖:
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiInBnauQjMtQzLc5WYpR3ZuFWeuFWevwVbvN2Xzd2bsJmbj9CXt92YuM3ZvxmYuNmLzhGdhB3YpB3X39Fcvw1LcpDc0RHaiojIsJye.jpg)
在圖中,可以得出以下幾點資訊:
q Client類通過Factory類來擷取實作了IProduct的具體子類。
q Client類依賴IProduct接口,而不是依賴具體的子類。
q Factory類複雜建立具體的子類,向Client隐藏具體的細節。
現在網上購物已經很流行了,在選擇支付方式的時候,一般有幾種選擇,比如:網銀支付,貨到付款支付等。對于網銀支付,又可以進一步細分為:中國銀行支付、工商銀行支付等。不同的銀行支付,最後調用的接口都不一樣,而且以後系統可能會支援更多的銀行。是以在設計支付功能的時候需要考慮到擴充性。本例将會介紹如何采用工廠方法模式來實作支付功能。
請看下圖:
下面我們就通過代碼來講述:(大家可以一起動手)
IPayment支付方式的接口代碼如下所示:
public interface IPayment
{
bool Payfor(decimal money);
}
複制代碼
支付實作者ABCPayment支付類的代碼如下所示:
public class ABCPayment:IPayment
{
public bool Payfor(decimal money)
{
//調用中國農業銀行提供的支付接口進行支付
return true;
}
}
ICBCPayment、AOCPayment的實作同理。
PaymentFactory的任務就是根據傳入的條件來建立不同的具體支付者:
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();
}
return result;
當然,可以采用更好的方式來實作PaymentFactory的CreatePayment方法,例如采用配置檔案,動态加載程式集的方式。
Decorator
為了更好地了解“裝飾”的概念,我們首先抛開枯燥的闡述,來看看現在流行的網遊。在網遊中玩家可以給自己的賬号購買不同的裝備,而且不同的裝備其特性也不一樣,比如重量、防禦能力、攻擊能力等。下面就以裝備中的铠甲為引子來講述“裝飾”。
下面,我們就看看如何實作铠甲的更新功能:從最初的青銅甲一步步更新到麒麟甲。
其中:
Knight:代表武将。
IArmour:铠甲接口。QTArmour為青銅铠甲,BLGJArmour為百煉鋼甲,QLArmour為麒麟甲。
每次铠甲更新,都是通過工廠武将建立新的铠甲子類替換原來的铠甲。
如果以後有新的铠甲或要對現有的铠甲功能進行增強,可以采用繼承的方式實作。例如現在麒麟铠甲要增加隐形功能,本着“開放關閉原則”,最容易想到的就是添加一個新的子類,從QLArmour(青銅铠甲)繼承現有的功能,同時再加上新的功能。如果再要新加上其他功能,其步驟也與此類似,原本就想通過繼承來重用現有的代碼,現在這個目的達到了,但是最後系統中存在了很多的功能相近的類,導緻類的數目急劇膨脹。
如果能夠在現有铠甲上面通過不斷的改造,增加新的功能,類似于變形金剛變身那樣,使加入了新功能的青銅甲铠甲演變成麒麟甲,成為新類型的铠甲,那麼類的數目就不會像之前那樣膨脹了。
網遊的例子到此暫告一個段落,主要就是想讓大家了解一下“裝飾”的含義,至于如何實作,在講完下面的例子之後大家就清楚了。
要遵循“開放關閉”原則,同時又要規避使用繼承帶來的類膨脹問題,如何實作?裝飾者模式回答了這個問題。
如圖,先不管圖中類名的定義,首先看看主要類的含義:
(1) OnlineSitePriceDecorator代表購物站點的打折。
(2) SupplierPriceDecorator代表供應商的打折。
(3) PolicyPriceDecorator代表政府要求的打折。
在打折的時候,需要考慮:打折就是改變産品的價格,而很多時候,價格往往隻是産品的一個屬性,例如,通常會采用decimal等資料類型。
現在因為價格總是在不斷地根據打折算法的變換而變化,那麼現在“價格”就成了一個變化點;另一方面,更加準确的說:打折算法是用在價格之上的,這樣才能實作對産品的打折。考慮把價格這個變化點引出去,成為一個業務實體Price,然後把打折算法都累積在這個實體上面進行,産品類Product絲毫不知道Price類是否應用了打折算法,隻管引用Price擷取最後的價格。
public interface IPrice
{
decimal Cost { get; set; }
public class Product
{
public string Name { get; set; }
public IPrice Price { get; set; }
}
下面,開始添加不同打折算法的實作。
首先我們來回想一下之前裝備更新的例子,我們是希望通過不斷地改造青銅甲,在原有的基礎上加上新的功能,最後達到裝備更新的目的。此時,在價格打折上面,因為同時要采用很多的打折算法,也類似于給價格不斷的“更新”:在原有的價格上不斷進行包裝。是以OnlineSitePriceDecorator購物網站推出的打折方法如下:
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。在經過OnlineSitePriceDecorator包裝之後把價格抛出來,進行下一個包裝:供應商打折。供應商打折的代碼如下所示:
public class SupplierPriceDecorator : IPrice
public SupplierPriceDecorator(IPrice price)
return price.Cost * 0.85M;
下面看看如何實作累積打折算法,代碼如下:
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);
}
}
價格包裝的過程如圖所示。
以上就是本篇的内容,講述的很粗略,希望見諒,還沒有寫完,待續!J
- 打賞
- 贊
- 收藏
- 評論
-
分享
微網誌
QQ
微信
走向.NET架構設計—第五章—業務層模式,原則,實踐(中篇) - 舉報