走向.NET架構設計—第五章—業務層模式,原則,實踐(後篇)
走向.NET架構設計—第五章—業務層模式,原則,實踐(後篇)
前言:在上一篇文章中,講述了一些設計模式的使用,本篇首先接著介紹還沒有講完的一些設計模式,然後再講述一些架構模式中的超類模式,作為本篇的結尾。
本篇的議題如下:架構模式設計模式設計原則
設計模式
本篇文章主要是接著討論的在業務層可以採用的或者常用的一些設計模式:
Factory Method
Decorator
State
Strategy
State模式
狀態模式允許一個物件在隨著它的狀態變化而改變它自身的一些行為。
在專案開發的過程中,有一些類,例如一個業務類常常是有自己的一些狀態的,而且還存在狀態之間的一些轉換,有些狀態之間是可以進行轉換的,有些狀態之間是不能轉換的。就拿一個汽車來舉例子,汽車有很多的狀態:靜止,啟動,前進,後退,停車。而且不能由”前進”狀態轉為“啟動”狀態。
很多朋友知道state模式的用法和結構,朋友們應該也清楚在狀態之間的轉換用swtich.. case的一些弊端。在專案中,很多時候就沒有”一定”,”非得”要用state模式來解決類似的問題,即使可以用state模式來解決。如果變化不大,switch.. case就夠用了。
下面還是來首先來看看使用state模式的一些例子。
還是採用電子商務為背景來舉例:每一個訂單都是有狀態的:New(新的),Shipped(已經發貨),Canceled(已取消)。我們知道一個新的訂單可以被變為”取消”的狀態,也可以成為”已發貨”狀態。但是訂單不能從”已發貨”狀態,變為”取消”的狀態。
下面就是例子中的類圖:
首先還是建立一個名為: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; }
}
{
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
}
{
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;
}
}
{
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:
//.... do some things
break;
case OrderStatus.Canceled:
//.... do some things
break;
}
}
public void ChangeStatus()
{
switch (Status)
{
case OrderStatus.New:
//.... do some things
break;
case OrderStatus.Shipped:
//.... do some things
break;
case OrderStatus.Canceled:
//.... do some things
break;
}
}
我們知道其實此時就是由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)
{
return true;
}
public void Cancel(Order order)
{
order.Change(new OrderCanceledState());
}
public new Order(OrderNewState newStatus);
}
{
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)
{
return true;
}
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!");
}
public OrderStatus Status
{
get { return OrderStatus.Shipped; }
}
public bool CanCancel(Order Order)
{
return false;
}
public void Cancel(Order order)
{
throw new NotImplementedException("You can't ship a shipped order!");
}
}
{
public bool CanShip(Order order)
{
return false;
}
public void Ship(Order order)
{
throw new NotImplementedException("You can't ship a shipped order!");
}
public OrderStatus Status
{
get { return OrderStatus.Shipped; }
}
public bool CanCancel(Order Order)
{
return false;
}
public void Cancel(Order order)
{
throw new NotImplementedException("You can't ship a shipped order!");
}
}
3. Canceled狀態也同理,我這裡就不在贅述了。
程式碼
public class OrderCanceledState : IOrderState
{
public bool CanShip(Order Order)
{
return false;
}
public void Ship(Order Order)
{
throw new NotImplementedException("You can't ship a cancelled order!");
}
public OrderStatus Status
{
get { return OrderStatus.Canceled; }
}
public bool CanCancel(Order Order)
{
return false;
}
public void Cancel(Order order)
{
throw new NotImplementedException("You can't ship a cancelled order!");
}
}
{
public bool CanShip(Order Order)
{
return false;
}
public void Ship(Order Order)
{
throw new NotImplementedException("You can't ship a cancelled order!");
}
public OrderStatus Status
{
get { return OrderStatus.Canceled; }
}
public bool CanCancel(Order Order)
{
return false;
}
public void Cancel(Order order)
{
throw new NotImplementedException("You can't ship a cancelled order!");
}
}
我們用一個UML圖來結束state模式的講述:
Strategy模式
其實策略模式,我這裡不打算作太多的講述,其實這種模式大家到處可見,我們常常在ASP.NET中常常提起的Provider模式,其實就是策略模式的一種實現。
大家看看結構圖,基本上就明白了:
在上述的圖中Context依賴一個IStrategy介面,我們可以決定讓Context使用IStrategy的任意的一個實現者:ConcreteStrategyA 或者ConcreteStrategyB。其實就是可以替換不同的實現者。可能大家在資料訪問層那塊有的體驗更加的明顯:定義一個IDataProvider,然後實現一個AdoDotNetProvider和一個LinqToSqlProvider。
架構模式
下面就來補充一些架構模式的知識,下文主要講述:Layer Supertype模式(超類模式)
超類模式就是定義一個基類,然後其他的所有的類都從這個類中繼承。對於業務層而言,在超類中可能會定義一些通用的業務規則和驗證方法,這樣就這些程式碼被到處分散。也體現了繼承的一個好處。
下面我們就來看一個專案中的例子(電子商務為例),類結構如下:
大家可以看到,所有的業務類都是從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> GetBrokenBusine***ules()
{
return _brokenRules;
}
protected void AddBrokenRule(string brokenRule)
{
_brokenRules.Add(brokenRule);
}
}
{
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> GetBrokenBusine***ules()
{
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.");
}
}
{
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不為空。至於如何呼叫這些驗證規則,在超類中已經實現了,此時業務類就“輕鬆”了很多—起碼不用再次寫那些相類似的程式碼了,實現了一定程度上的程式碼重用。
今天就講到這裡了,不正確之處,還望朋友們指出,見諒!
多謝支援!
相關文章
- 軟體架構設計原則和模式(上):分層架構設計架構模式
- 《JavaScript設計模式與開發實踐》原則篇(2)—— 最少知識原則JavaScript設計模式
- 設計和架構:業務開發指導原則架構
- 《JavaScript設計模式與開發實踐》原則篇(1)—— 單一職責原則JavaScript設計模式
- 《JavaScript設計模式與開發實踐》原則篇(3)—— 開放-封閉原則JavaScript設計模式
- C#實踐設計模式原則SOLIDC#設計模式Solid
- .NET 雲原生架構師訓練營(設計原則&&設計模式)--學習筆記架構設計模式筆記
- 實戰解析Android架構設計原則Android架構
- SOLID架構設計原則Solid架構
- 如何實踐設計原則
- 利用WMRouter 重新架構設計業務模式架構模式
- App架構設計經驗談:業務層的設計APP架構
- 中介者設計模式——業務實踐設計模式
- 雲原生架構及設計原則架構
- 解析 Android 架構設計原則Android架構
- 微服務架構的4大設計原則和一個平臺實踐微服務架構
- .Net Core後端架構實戰【1-專案分層框架設計】後端架構框架
- .NET應用架構設計—面向查詢的領域驅動設計實踐(調整傳統三層架構,外加維護型的業務開關)應用架構
- 設計原則 設計模式設計模式
- 設計模式 - 設計原則設計模式
- 【設計模式】設計原則設計模式
- 實踐GoF的23種設計模式:SOLID原則(上)Go設計模式Solid
- 架構整潔之道二(設計原則)架構
- 設計模式的設計原則設計模式
- [分散式]架構設計原則--高併發分散式架構
- 簡單介紹架構設計的原則!架構
- 【設計模式——六原則】設計模式
- [.net 物件導向程式設計深入](18)實戰設計模式——設計模式使用場景及原則物件程式設計設計模式
- 網易考拉規則引擎平臺架構設計與實踐架構
- 【架構與設計】常見微服務分層架構的區別和落地實踐架構微服務
- .Net微服務實戰之技術架構分層篇微服務架構
- 設計模式總結(實踐篇1)設計模式
- Javascript 設計模式之設計原則JavaScript設計模式
- JavaScript設計模式(一)設計原則JavaScript設計模式
- 設計模式(07)——設計原則(2)設計模式
- 設計模式(06)——設計原則(1)設計模式
- 設計模式學習-設計原則設計模式
- 360°透視:雲原生架構及設計原則架構