Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a pattern for adding "options" to a class?

I have a class on which I want to allow several (~20+) configuration options. Each option turns on or off a piece of functionality, or otherwise alters operations. To facilitate this, I coded a separate options class with default values. However, I had to litter my code with guard conditions to determine how methods should behave. I am almost done, but now the code seems to smell.

Is there a preferred method/pattern to implement a class like this?

EDIT: More specifically, I am working on a parsing class. Each option configures mutually exclusive portions of the basic parsing algorithm. For example I have several areas in my class that look like the below:

 if (this.Option.UseIdAttribute)
      attributeIDs = new Hashtable();
 else
      attributeIDs = null;


    public Element GetElementById(string id)
    {
        if (string.IsNullOrEmpty (id))
            throw new ArgumentNullException("id");

        if (attributeIDs == null)
            throw new Exception(ExceptionUseIdAttributeFalse);

        return attributeIDs[id.ToLower()] as Element;
    }
like image 506
Nescio Avatar asked Oct 18 '08 10:10

Nescio


3 Answers

How about the Decorator pattern? It's designed for dynamically adding behavior to a class.

like image 141
Thomas Owens Avatar answered Oct 02 '22 09:10

Thomas Owens


There is indeed another pattern called the builder pattern exactly for this purpose. Its usually, useful when you have a class but each 'configuration' option could be made optional perhaps in some combinations only. (http://en.wikipedia.org/wiki/Builder_pattern, but that doesnt exactly describe my scenario tho).

You create two classes - the class you want to build, and the builder. The builder class is the class that takes care of working out which combinations of options are optional, which combination makes sense, etc etc.

e.g., you want to represent a salad - but only certain ingredients 'tastes good', so only those should be made.

Class Salad {
   private Veggie v;
   private Egg e;
   private Meat m;
   // etc etc, lots of properties
   //constructor like this is nice
   Salad(SaladBuilder builder) {
      //query the builder to actually build the salad object. 
      //getVeggie() will either return the supplied value, 
      //or a default if none exists. 
      this.v = builder.getVeggie(); 
      //rest of code omitted
   }

   //otherwise this constructor is fine, but needs a builder.build() method
   Salad(Veggie v, Meat m, Egg e) { //code omitted
   }
}

class SaladBuilder {
   //some default, or left to null depending on what is needed
   private Veggie v = SOME_DEFAULT_VEGGIE;
   private Egg e; 
   private Meat m;
   // etc etc, lots of properties.

   //similar functions for each ingredient, 
   //or combination of ingredients that only make sense together 
   public SaladBuilder addIngredient(Meat m) {
      this.m = m;
      return this;
   }

   public SaladBuilder addIngredient(Veggie v) {
      this.v = v;
      return this;
   }

   public Salad build(){
      // essentially, creates the salad object, but make sure optionals
      // are taken care of here.
      return new Salad(getBeggie(), getMeat(), getEgg());
   }
}

usage example

Salad s = new SaladBuilder().addIngredient(v).addIngredient(m).build();
like image 36
Chii Avatar answered Oct 02 '22 09:10

Chii


For the options that turn on/off functionality, I think Decorator is the way to go as @Thomas Owens says. I'm a little more concerned about the options that alter functions. Decorator many not work if these operations cannot be chained. For example, if your code looks like:

public void ActionABC()
{
   if (options.DoA)
   {
      A();
   }

   if (options.DoB)
   {
      B();
   }

   if (options.DoC)
   {
      C();
   }
}

public void ActionCAB()
{
   if (options.DoC)
   {
      C();
   }

   if (options.DoA)
   {
      A();
   }

   if (options.DoB)
   {
      B();
   }
}

This would be difficult to handle with Decorator as the order of composition differs for for each Action method.

With 20+ options, assuming that they are on/off, you have over 400 different possible combinations. I suspect that not all of these combinations are equally likely. For things that you can't handle via Decorator, you might want to think about modes of operation that map on to combinations of settings. Support only those modes that are most expected. If the number of modes is small you could handle this with subclassing, then use the Decorators to add functionality to the subclass representing the mode the user has chosen. You could use a Factory to select and build the proper class based on the configuration.

In essence, I guess I'm saying that you may want to consider if you need as much flexibility, and attendant complexity, as you are building. Consider reducing the number of configuration options by collapsing them into a smaller number of more likely to be used modes.

like image 31
tvanfosson Avatar answered Oct 02 '22 08:10

tvanfosson