After Thought

Eliminate if else using Smart Enums

with 4 comments

Open/Close principle (SOLID) states that class should be Open for extension and closed for modification. One way to achieve this is to eliminate conditional statements (if…else) in our code. Continuing our example of PlasticType from the Smart Enums post, let us say we have to write a method that has to decide the recycling program based on the plastic type.

public class Controller
{
	private readonly IRecycleManager _recycleManager;

	public Controller(IRecycleManager recycleManager)
	{
		_recycleManager = recycleManager;
	}

	public void Recycle(PlasticData plasticData)
	{
		if (plasticData.PlasticType == "pet")
		{
			_recycleManager.RecycleType1(plasticData);
		}
		if (plasticData.PlasticType == "hdpe")
		{
			_recycleManager.RecycleType2(plasticData);
		}
		if (plasticData.PlasticType == "pvc")
		{
			_recycleManager.RecycleType3(plasticData);
		}
	}
}

In the above example, we inject RecycleManager in to our Controller class that is responsible for recycling the plastic. The Recycle method calls the appropriate recycling program based on the plastic type supplied in the PlasticData model.

public class PlasticData
{
	public string PlasticType { get; set; }
	public decimal Weight { get; set; }
	public string Color { get; set; }
}

 

 

public interface IRecycleManager
{
	void RecycleType1(PlasticData plasticData);
	void RecycleType2(PlasticData plasticData);
	void RecycleType3(PlasticData plasticData);
}

 

 

public class RecycleManager : IRecycleManager
{
	public void RecycleType1(PlasticData plasticData)
	{
		// code here
	}

	public void RecycleType2(PlasticData plasticData)
	{
		// code here
	}

	public void RecycleType3(PlasticData plasticData)
	{
		// code here
	}
}

 

We see that Recycle method is filled with multiple conditional statements making it open to modification violating the Open/Close principle. The reason I say it is open to modification is because if we want to add recycling program to another type of plastic in future, we have to add another conditional statement and add another method to RecycleManager class. It also makes our tests less maintainable and brittle. If we can eliminate the conditional statements in the Recycle method, we have a good chance of making this code adhere to Open/Close principle. One effective way of doing this is to use Smart Enums. Read more about about Smart Enums here. Let us go ahead and add a behavior to PlasticType from the previous post as shown below.

public class PlasticType
{
	public static PlasticType PET = new PlasticType("pet", "Polyethylene Terephthalate",
													(recycleManager, plasticData) =>
													recycleManager.RecycleType1(plasticData));

	public static PlasticType HDPE = new PlasticType("hdpe", "High-density Polyethylene",
													 (recycleManager, plasticData) =>
													 recycleManager.RecycleType2(plasticData));

	public static PlasticType PVC = new PlasticType("pvc", "Polyvinyl Chloride", 
													(recycleManager, plasticData) =>
													recycleManager.RecycleType3(plasticData));

	private PlasticType(string key, string description, Action<IRecycleManager, PlasticData> recycle)
	{
		Key = key;
		Description = description;
		Recycle = recycle;
		NamedConstants.Add(key, this);
	}


	public static PlasticType GetFor(string key)
	{
		if (key == null)
		{
			return null;
		}

		PlasticType plasticType;
		NamedConstants.TryGetValue(key, out plasticType);
		return plasticType;
	}

	private static readonly Dictionary<string, PlasticType> NamedConstants = new Dictionary<string, PlasticType>();

	public string Key { get; set; }
	public string Description { get; set; }
	public Action<IRecycleManager, PlasticData> Recycle;
}

Now the plastic type also defines the recycling program that it is associated with. Now let us go ahead an modify our Recycle method in the Controller class.

public class Controller
{
	private readonly IRecycleManager _recycleManager;

	public Controller(IRecycleManager recycleManager)
	{
		_recycleManager = recycleManager;
	}

	public void Recycle(PlasticData plasticData)
	{
		PlasticType.GetFor(plasticData.PlasticType).Recycle(_recycleManager, plasticData);
	}
}

We see that the Recycle method is reduced to just one line and we got rid of all the conditional statements in the method. Now our Controller is open to extension and closed to modification. If were to add a new recycling program for another type of plastic in the future, we just have to add another method to RecycleManager class.

Advertisements

Written by shashankshetty

July 18, 2010 at 10:39 pm

Posted in C#, Uncategorized

Tagged with

4 Responses

Subscribe to comments with RSS.

  1. […] You can create a Smart Enum as described above without a key or description. It depends on the problem you are trying to solve. « Separation of concerns in Input Builders Eliminating if else in the code using Smart Enums » […]

    • PlasticType.GetFor(plasticData.PlasticType).Recycle(_recycleManager, plasticData);

      Does this mean PlasticType will have method for Recycle?

      How about this:

      public interface IRecycleManager
      {

      PlasticType {get;set;}
      Recyle(PlasticData plasticData);

      }

      Implement separate IRecycleManager for each plastic type.

      Inject Array Of IRecycleManager to controller.

      public Controller(IRecycleManager[] recycleManagers)

      Controller.Recycle(PlasticData plasticdata)

      var recycleManager = _recycleManagers.SingleOrDefault(x=>x.PlasticType==plasticdata.PlasticType);

      recycleManager.Recycle(plasticData);

      Reddy Rajanala

      July 27, 2010 at 8:45 am

      • That would be the best way to go.

        shashankshetty

        July 27, 2010 at 12:05 pm

  2. Good blog post…..

    Dhili Sriramulu

    September 16, 2010 at 8:38 am


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: