views:

154

answers:

5
+4  A: 

What you're implementing is a Factory Pattern. This is a standard practice, though it typically means writing a lot of repetitive code (much like your switch statement, which is often how they're implemented). You could do all sorts of fancy things like dynamic instantiation via reflection, but don't play with fire. Just stick with switch statement and you'll be fine.

Adam Robinson
A: 

You could implement this with a custom attribute and a factory method. Make all you Sub Classes implement a CustomAttribute say CheckOutCaseScenarioAttribute that takes the CheckOutCase Enum value.

Within your factory method, look for types that have this Enum Value set and create the object. This will avoid your switch case. This will work if you dont have any other initialization logic within your factory method.

Vasu Balakrishnan
A: 

This is called a Factory Design Pattern. I would create a static method that returns the needed class. A good practice here is to implement an Interface and return the interface.

interface ICheckoutItem
{
    void CheckOut();
}

Have your items implement the interface. Then in your factory method return the interface of each item.

ICheckoutItem chooseSubclass(CheckoutCase c)
{
ICheckoutItem output;
    switch (c):
    {
       case CheckoutCase.SingleItemNew:
         output = new SingleItemNew;
         break;
       case . . . 
  return output;
    }
}
Stan R.
What advantage is there to returning an interface instead of a base class? If there's no advantage then this answer is identical to the current solution.
Jamie Ide
i wrote this as someone else wrote the current answer above me..in fact I even upvoted his answer. Interfaces are better since you may have items that eventually will not inherit from the same Base class but still need to be "Checked Out", at that point you will need minimum refactoring as your methods and logic will not depend on a specific class.
Stan R.
+1  A: 

If there are a large number of cases, I would create a Dictionary<CheckoutCase, Type> and populate it one time with the set of all CheckoutCase values and corresponding CheckoutContext Types. Then you could use Activator.CreateInstance to return the appropriate type instead of a gigantic switch statement.

Jamie Ide
I eventually went with this version, the case was getting too hard to read!
Ed Woodcock
A: 

You can create an attribute that has one property which would be the type of CheckoutContext:

public class CheckoutContextAttribute : Attribute
{
   public Type CheckoutType{get;set;}
}

Then, on your enum, you can put the correct attribute on the correct enum type:

public enum CheckoutCase
{
   [CheckoutContext(CheckoutType=typeof(SingleItemNew)]
   SingleItemNew,
   ...
   ...
}

Then, in that method where you need to send back the correct Context type you use reflection and do something like this:

public CheckoutContext GetContext(CheckoutCase c)
{
   FieldInfo field = c.GetType().GetField(c.ToString());
   object[] attribs = field.GetCustomAttributes(typeof(CheckoutContextAttribute),false);
   CheckountContext result = null;
   if(attribs.Length > 0)
   {
      CheckoutContextAttribute attrib = attribs[0] as CheckoutContextAttribute;
      Type type = attrib.CheckoutType;
      result = Activator.CreateInstance(type) as CheckountContext;
   }

   return result;
}

This should do the trick. Just add some null / error checking to be safe.

BFree