Routing an object in C# without using switch statements

折月煮酒 提交于 2019-12-13 06:48:28

问题


I am writing a piece of software in c# .net 4.0 and am running into a wall in making sure that the code-base is extensible, re-usable and flexible in a particular area.

We have data coming into it that needs to be broken down in discrete organizational units. These units will need to be changed, sorted, deleted, and added to as the company grows.

No matter how we slice the data structure we keep running into a boat-load of conditional statements (upwards of 100 or so to start) that we are trying to avoid, allowing us to modify the OUs easily.

We are hoping to find an object-oriented method that would allow us to route the object to different workflows based on properties of that object without having to add switch statements every time.

So, for example, let's say I have an object called "Order" come into the system. This object has 'orderItems' inside of it. Each of those different kinds of 'orderItems' would need to fire a different function in the code to be handled appropriately. Each 'orderItem' has a different workflow. The conditional looks basically like this -

if(order.orderitem == 'photo')
  {do this} 
else if(order.orderitem == 'canvas')
  {do this}

edit: Trying to clarify.


回答1:


I'm not sure your question is very well defined, you need a lot more specifics here - a sample piece of data, sample piece of code, what have you tried...

No matter how we slice the data structure we keep running into a boat-load of conditional statements (upwards of 100 or so to start) that we are trying to avoid

This usually means you're trying to encode data in your code - just add a data field (or a few).

Chances are your ifs are linked to each other, it's hard to come up with 100 independent ifs - that would imply you have 100 independent branches for 100 independent data conditions. I haven't encountered such a thing in my career that really would require hard-coding 100 ifs.

Worst case scenario you can make an additional data field contain a config file or even a script of your choice. Either case - your data is incomplete if you need 100 ifs


With the update you've put in your question here's one simple approach, kind of low tech. You can do better with dependency injection and some configuration but that can get excessive too, so be careful:

public class OrderHandler{ 
  public static Dictionary<string,OrderHandler> Handlers = new Dictionary<string,OrderHandler>(){
  {"photo", new PhotoHandler()},
  {"canvas", new CanvasHandler()},
};

  public virtual void Handle(Order order){
    var handler = handlers[order.OrderType];
    handler.Handle(order);
  } 
}

public class PhotoHandler: OrderHandler{...}
public class CanvasHandler: OrderHandler{...}



回答2:


What you could do is called - "Message Based Routing" or "Message Content Based" Routing - depending on how you implement it.

In short, instead of using conditional statements in your business logic, you should implement organizational units to look for the messages they are interested in.

For example: Say your organization has following departments - "Plant Products", "Paper Products", "Utilities". Say there is only one place where the orders come in - Ordering (module).
here is a sample incoming message.

Party:"ABC Cop"
Department: "Plant Product"
Qty: 50
Product: "Some plan"

Publish out a message with this information. In the module that processes orders for "Plant Products" configure it such that it listens to a message that has "Department = Plant Products". This way, you push the onus on the department modules instead of on the main ordering module.

You can do this using NServiceBus, BizTalk, or any other ESB you might already have.

This is how you do in BizTalk and this is how you can do in NServiceBus




回答3:


Have you considered sub-typing OrderItem?

public class PhotoOrderItem : OrderItem {}
public class CanvasOrderItem : OrderItem {}

Another option would be to use the Strategy pattern. Add an extra property to your OrderItem class definition for the OrderProcessStrategy and use a PhotoOrderStrategy/CanvasOrderStrategy to contain all of the different logic.

public class OrderItem{
   public IOrderItemStrategy Strategy;
}

public interface IOrderItemStrategy{
   public void Checkout();
   public Control CheckoutStub{get;}
   public bool PreCheckoutValidate();
}

public class PhotoOrderStrategy : IOrderItemStrategy{}
public class CanvasOrderStrategy : IOrderItemStrategy{}



回答4:


Taking the specific example: You could have some Evaluator that takes an order and iterates each line item. Instead of processing if logic raise events that carry in their event arguments the photo, canvas details.

Have a collection of objects 'Initiators' that define: 1)an handler that can process Evaluator messages, 2)a simple bool that can be set to indicate if they know what to do with something in the message, and 3)an Action or Process method which can perform or initiate the workflow. Design an interface to abstract these.

Issue the messages. Visit each Initiator, ask it if it can process the lineItem if it can tell it to do so. The processing is kicked off by the 'initiators' and they can call other workflows etc.

Name the pieces outlined above whatever best suits your domain. This should offer some flexibility. Problems may arise depending on concurrent processing requirements and workflow dependencies between the Initiators.

In general, without knowing a lot more detail, size of the project, workflows, use cases etc it is hard to comment.



来源:https://stackoverflow.com/questions/24268013/routing-an-object-in-c-sharp-without-using-switch-statements

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!