天天看點

一起談.NET技術,走向ASP.NET架構設計——第五章:業務層模式,原則,實踐(後篇)

  設計模式

  本篇文章主要是接着讨論的在業務層可以采用的或者常用的一些設計模式:

  State模式

  狀态模式允許一個對象在随着它的狀态變化而改變它自身的一些行為。

  在項目開發的過程中,有一些類,例如一個業務類常常是有自己的一些狀态的,而且還存在狀态之間的一些轉換,有些狀态之間是可以進行轉換的,有些狀态之間是不能轉換的。就拿一個汽車來舉例子,汽車有很多的狀态:靜止,啟動,前進,後退,停車。而且不能由”前進”狀态轉為“啟動”狀态。

  很多朋友知道state模式的用法和結構,朋友們應該也清楚在狀态之間的轉換用swtich.. case的一些弊端。在項目中,很多時候就沒有”一定”,”非得”要用state模式來解決類似的問題,即使可以用state模式來解決。如果變化不大,switch.. case就夠用了。

  下面還是來首先來看看使用state模式的一些例子。

  還是采用電子商務為背景來舉例:每一個訂單都是有狀态的:New(新的),Shipped(已經發貨),Canceled(已取消)。我們知道一個新的訂單可以被變為”取消”的狀态,也可以成為”已發貨”狀态。但是訂單不能從”已發貨”狀态,變為”取消”的狀态。

  下面就是例子中的類圖:

一起談.NET技術,走向ASP.NET架構設計——第五章:業務層模式,原則,實踐(後篇)

  首先還是建立一個名為:ASPPatterns.Chap5.StatePattern的解決方案,添加一個名為:ASPPattern.Chap5.StatePattern.Model的類庫:

  然後添加在Model的類庫中添加一個表示狀态接口的定義:IOrderState:

public interface IOrderState

{

bool CanShip(Order Order);

void Ship(Order Order);

bool CanCancel(Order Order);

void Cancel(Order order);

OrderStatus Status { get; }

}

  下面來定義個表示訂單狀态的枚舉:

public enum OrderStatus

New = 0,

Shipped = 1,

Canceled = 2

  然後我們來看看,真正要進行狀态轉化的那個訂單類:

public class Order

private IOrderState _orderState;

public Order(IOrderState baseState)

_orderState = baseState;

public int Id { get; set; }

public string Customer { get; set; }

public DateTime OrderedDate { get; set; }

public OrderStatus Status()

return _orderState.Status;

public bool CanCancel()

return _orderState.CanCancel(this);

public void Cancel()

if (CanCancel())

_orderState.Cancel(this);

public bool CanShip()

return _orderState.CanShip(this);

public void Ship()

if (CanShip())

_orderState.Ship(this);

internal void Change(IOrderState OrderState)

_orderState = OrderState;

  其實狀态模式一個最主要的思想就是:把狀态之間的轉換分離出來,把每一個狀态分解為一個個的狀态的類,然後這些狀态來負責如何在不同的狀态之間的轉換。也就是說,就本例而言,以前我們會在Order類中寫上如下的語句:

public void ChangeStatus()

switch (Status)

case OrderStatus.New:

//.... do some things

break;

case OrderStatus.Shipped:

case OrderStatus.Canceled:

  我們知道其實此時就是由Order類來控制了狀态之間的轉換。其實state模式的就是讓那些“狀态”變為一個“有思想”的狀态類,這些類自己來負責如何以及何時轉換到其他的狀态,這樣Order的“負擔”就減輕了。還有一個就是大家常常會”批判”:如何要添加一個新的狀态,那麼ChangeStatus方法勢必會變化,因為這個方法控制了狀态之間的轉換,如果把狀态的轉換邏輯分離出去,最好做到添加或者減少狀态都不會影響現有的Order就更好了。

  下面的講述有點直接,希望不熟悉state模式的朋友先“撐下去”J

  1、當建立一個訂單的時。候,這個訂單的狀态肯定就是”New”(新的)。那麼我們可能就傳入一個表示“New”狀态的類:OrderNewStatus:

  new Order(OrderNewState newStatus)

  OrderNewStatus把訂單的狀态标記為New

  我們知道:訂單的狀态為New的時候,狀态可以向Canceled和Shipped轉換,那麼OrderNewStatus的定義可能如下:

public class OrderNewState : IOrderState

public bool CanShip(Order Order)

return true;

public void Ship(Order Order)

Order.Change(new OrderShippedState());

public OrderStatus Status

get { return OrderStatus.New; }

public bool CanCancel(Order Order)

public void Cancel(Order order)

order.Change(new OrderCanceledState());

public new Order(OrderNewState newStatus);

  2、當新建立的訂單處理到一定的流程的時候,例如要發貨了,此時要更新訂單的狀态,此時我們隻要調用Order的ship方法就行了。其實此時我們就是在調用NewOrderStatus類的Ship方法,這個類的ship方法知道怎麼做:先判斷Order的是否可以向Shipped狀态轉換(調用CanShip方法),如果可以,那麼就new一個OrderShippedStatus狀态的類,然後用這個類去替換原來的NewOrderStatus(調用Order類的Change方法),這樣,Order的狀态就是Shipped了,但是Order完全不用管狀态之間是如何變化的。

public class OrderShippedState : IOrderState

public bool CanShip(Order order)

return false;

public void Ship(Order order)

throw new NotImplementedException("You can't ship a shipped order!");

get { return OrderStatus.Shipped; }

  3、Canceled狀态也同理,我這裡就不在贅述了。

public class OrderCanceledState : IOrderState

throw new NotImplementedException("You can't ship a cancelled order!");

get { return OrderStatus.Canceled; }

  我們用一個UML圖來結束state模式的講述:

一起談.NET技術,走向ASP.NET架構設計——第五章:業務層模式,原則,實踐(後篇)

  Strategy模式

  其實政策模式,我這裡不打算作太多的講述,其實這種模式大家到處可見,我們常常在ASP.NET中常常提起的Provider模式,其實就是政策模式的一種實作。

  大家看看結構圖,基本上就明白了:

一起談.NET技術,走向ASP.NET架構設計——第五章:業務層模式,原則,實踐(後篇)

  在上述的圖中Context依賴一個IStrategy接口,我們可以決定讓Context使用IStrategy的任意的一個實作者:ConcreteStrategyA 或者ConcreteStrategyB。其實就是可以替換不同的實作者。可能大家在資料通路層那塊有的體驗更加的明顯:定義一個IDataProvider,然後實作一個AdoDotNetProvider和一個LinqToSqlProvider。

  架構模式

  下面就來補充一些架構模式的知識,下文主要講述:Layer Supertype模式(超類模式)

  超類模式就是定義一個基類,然後其他的所有的類都從這個類中繼承。對于業務層而言,在超類中可能會定義一些通用的業務規則和驗證方法,這樣就這些代碼被到處分散。也展現了繼承的一個好處。

  下面我們就來看一個項目中的例子(電子商務為例),類結構如下:

一起談.NET技術,走向ASP.NET架構設計——第五章:業務層模式,原則,實踐(後篇)

  大家可以看到,所有的業務類都是從EntityBase繼承的。

public abstract class EntityBase<T>

private T _Id;

private bool _idHasBeenSet = false;

private IList<string> _brokenRules = new List<string>();

public EntityBase()

{ }

public EntityBase(T Id)

this.Id = Id;

public T Id

get { return _Id; }

set

if (_idHasBeenSet)

ThrowExceptionIfOverwritingAnId();

_Id = value;

_idHasBeenSet = true;

private void ThrowExceptionIfOverwritingAnId()

throw new ApplicationException("You cannot change the id of an entity.");

public bool IsValid()

ClearCollectionOfBrokenRules();

CheckForBrokenRules();

return _brokenRules.Count() == 0;

protected abstract void CheckForBrokenRules();

private void ClearCollectionOfBrokenRules()

_brokenRules.Clear();

public IEnumerable<string> GetBrokenBusinessRules()

return _brokenRules;

protected void AddBrokenRule(string brokenRule)

_brokenRules.Add(brokenRule);

  在這個超類中,提供了儲存每個業務類唯一辨別的邏輯,并且確定這個辨別一旦設定就不會被改變。而且這個超類還提供一些簡單的驗證邏輯。

  我們再來看看如何使用這個超類,下面定義了一個Customer的業務類:

public class Customer : EntityBase<long>

public Customer() { }

public Customer(long Id)

: base(Id)

public string FirstName { get; set; }

public string LastName { get; set; }

protected override void CheckForBrokenRules()

if (String.IsNullOrEmpty(FirstName))

base.AddBrokenRule("You must supply a first name.");

if (String.IsNullOrEmpty(LastName))

base.AddBrokenRule("You must supply a last name.");

  在這個類中,我們定義了唯一辨別的類型:long,而且還定義了一些業務規則:FirstName, LastName不為空。至于如何調用這些驗證規則,在超類中已經實作了,此時業務類就“輕松”了很多—起碼不用再次寫那些相類似的代碼了,實作了一定程度上的代碼重用。

  今天就講到這裡了,不正确之處,還望朋友們指出,見諒!

  多謝支援!

繼續閱讀