2017-09-16 58 views
0

我目前正在使用數據庫工作,其中有幾個只包含類型枚舉的表。事情是這樣:避免由於數據庫類型導致的switch語句

OrderStatus: 
ID | Description 
1 | Open 
2 | Shipped 
3 | Canceled 
... 

當我從數據庫中獲取的類型,要檢查他們的代碼,這通常會導致一個switch語句,這是有點難以維持尤其是當新的項目被添加到表中。

switch(order.OrderStatus.ID) { 
    case 1: 
     handleOpenOrder(); 
     break; 
    case 2: 
     handleShippedOrder(); 
     break; 
    case 3: 
     handleCanceledOrder(); 
     break; 
    default: 
     break; 
} 

通常人們會使用繼承來解決這個問題,但在這種情況下,我要檢查在某個時刻從數據庫返回值的類型。

我目前從數據庫中獲得orderstatus作爲正常orderstatus實體。有沒有辦法讓ORM(NHibernate)自動將實體轉換爲更具體的對象?像例如一個OrderStatusOpen類?

+0

是您的主要目的,避免了開關語句或自動化的具體訂單處理程序的創建? – khlr

+0

主要目標是避免switch語句,這樣如果添加新的oder狀態,我不必經過幾個固定switch語句的類。 – narain

+0

@narain給出這個描述,你的問題不是它是否是'switch'語句,而是你有完全相同的代碼分散在幾個類中,而不是在一個地方。無論是哪一個地方使用「開關」或其他機制,在任何情況下都不會產生任何影響。 – Servy

回答

0

如果訂單處理程序都包含在一個類,並只用在那裏,你可以簡單地這樣做以下,延長Dictionary<int, Action>當一個新的處理程序,方法的實現:

public class Foo 
{ 
    private readonly _handlerMap = new Dictionary<int, Action> 
    { 
     { 1,() => handleOpenOrder() }, 
     { 2,() => handleShippedOrder() }, 
     { 3,() => handleCanceledOrder() } 
    } 

    public void TheMethodPreviouslyContainingTheSwitch(Order order) 
    { 
     var action = _handlerMap[order.OrderStatus.ID]; 
     action.Invoke(); 
    } 
} 

如果您在幾個類中有switch-statement,我可能會爲每個處理程序實現一個類並提取匹配的接口。如有必要,我可以詳細說明。

編輯:

基於接口的方法,我腦子裏想的,是基本相同的。這可能還不是一切問題的答案;-) 我寫了這個從零開始(可能無法編譯):

public interface IOrderHandler 
{ 
    int StatusId { get; } 
    void Handle(Order order); 
} 

public class OpenOrderHandler : IOrderHandler 
{ 
    public int StatusId => 1; 

    public void Handle(Order order) 
    { 
     // ... 
    } 
} 

public class OrderHandlerFactory 
{ 
    // this factory could be injected to all you dependant classes that need 
    // handlers to handle orders 

    private readonly _handlerMap = new Dictionary<int, Action> 
    { 
     // defining the IDs here and in the classes' defintions may be a bit 
     // redudant, but... meh ;) 
     { 1,() => new OpenOrderHandler() }, 
     { 2,() => new ShippedOrderHandler() }, 
     { 3,() => new CancledOrderHandler() } 
    } 

    public IOrderHandler CreateHandlerByStatus(int orderStatusId) 
    { 
     // if the creation of a handler is expensive, it may be useful to 
     // only create a single handler that matches the orderStatusId 
     var action = _handlerMap[orderStatusId]; 
     var handler = action.Invoke(); 
     return handler; 
    } 

    public ICollection<IOrderHandler> CreateHandlers() 
    { 
     // it may be fine to create all handlers in each call of this method 
     // if the creation is inexpensive 
     return _handlerMap.Select(kvp => kvp.Value.Invoke()).ToList(); 
    } 
} 

public class Foo 
{ 
    private readonly OrderHandlerFactory _orderHandlerFactory; 

    public Foo(OrderHandlerFactory orderHandlerFactory) 
    { 
     _orderHandlerFactory = orderHandlerFactory; 
    } 

    public void TheMethodPreviouslyContainingTheSwitch(Order order) 
    { 
     var handler = _orderHandlerFactory.CreateHandlerByStatus(order.OrderStatus.ID); 
     handler.Handle(order); 
    } 

    public void ThisMayBeUsefulIfMultipleHandlersRelateToAcertainStatus(Order order) 
    { 
     var handlers = _orderHandlerFactory.CreateHandlers(); 
     handlers 
      .Where(handler => handler.StatusId == order.OrderStatus.ID) 
      .All(handler => handler.Handle(order)); 
    } 
} 
+0

每個處理程序有一個類將意味着我有某種類型的推論類型不是嗎?所以我會OpenStatus.class,ShippedStatus.class等,但我不明白如何才能工作,當我簡單地映射數據庫中的數據。 – narain

+0

ORM將能夠將表內容映射到_a某種類型的對象。但它只會以數據傳輸對象的方式進行。因此,從上面的三個示例條目中,您將獲得三個只將數據保存在兩個屬性中的對象:「ID」和「Description」。 – khlr

+0

準確地說。那麼,我將如何使用您提到的界面使用該方法? – narain