2017-09-16 59 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