Improve your UI code with Strategy Pattern


This article is intended to provide a brief introduction to the Strategy Design Pattern, and how can help us to improve our User Interface code.

The scenario – A simple blogging application

Blogging application - showing actions by role

You have a blog application and you want to limit user actions based on their roles.
You have the following roles:

  • User
  • Writer
  • Editor

and the following actions:

  • New Post – Creates a new blog post
  • Edit Post – Edits an existing blog post
  • Submit Post – Submits a post for approval
  • Reject Post – Rejects a previously submitted blog post
  • Publish Post – Publishes a previously submitted blog post

The table below shows the actions per role type

Actions

User

Writer

Editor

New post

x

Edit post

x

Submit post

x

Reject post

x

Publish post

x

Role type is represented by an enumeration:

public enum RoleType
{
    User,
    Writer,
    Editor
}

What’s the best solution for our problem?

Solution 1 – Using switch or if statements

Our code could have been written like this:

switch (CurrentRole)
{
    case RoleType.Editor:
        btEditPost.Visible = false;
        btNewPost.Visible = false;
        btPublishPost.Visible = true;
        btRejectPost.Visible = true;
        btSubmitPost.Visible = false;
        break;

    case RoleType.Writer:
        btEditPost.Visible = true;
        btNewPost.Visible = true;
        btPublishPost.Visible = false;
        btRejectPost.Visible = false;
        btSubmitPost.Visible = true;
        break;

    default:
        btEditPost.Visible = false;
        btNewPost.Visible = false;
        btPublishPost.Visible = false;
        btRejectPost.Visible = false;
        btSubmitPost.Visible = false;
        break;
}

// same code duplicated in several places

Some of the problems with this implementation are:
No separation of concerns – UI code (button visibility) is mixed with Business Logic code.
Code is harder to maintain – You can find yourself in a situation where you have to search in endless switch statements, just trying to change a simple thing. Things can get even worst if the same statements are duplicated in several places. What if you need to add a new role type?

Solution 2 – Strategy Pattern to the rescue!

Strategy Pattern definition:

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Step 1: “Program to an interface, not a concrete implementation”

If you depend on an interface you’re decoupled from the implementation. Implementation may change, or new implementations can be added without having to change the client application. You can also use an abstract class instead of an interface.

I’ve created an abstract class (BaseBehavior) that will be used by the client application:

public abstract class BaseBehavior
{
    public bool CanEdit { get; protected set; }
    public bool CanSubmit { get; protected set; }
    public bool CanReject { get; protected set; }
    public bool CanPublish { get; protected set; }
}

Each boolean property represents the existing actions. Let’s assume that CanEdit can be used to create a new post or edit an existing one

Step 2: Create a class that represents each role type

In each class it will be defined which actions are allowed for the respective role

public class UserBehavior : BaseBehavior
{
    public UserBehavior()
    {
        CanEdit = false;
        CanPublish = false;
        CanReject = false;
        CanSubmit = false;
    }
}

public class WriterBehavior : BaseBehavior
{
    public WriterBehavior()
    {
        CanEdit = true;
        CanPublish = false;
        CanReject = false;
        CanSubmit = true;
    }
}

public class EditorBehavior : BaseBehavior
{
    public EditorBehavior()
    {
        CanEdit = false;
        CanPublish = true;
        CanReject = true;
        CanSubmit = false;
    }
}

Step 3: Create a factory method
This is the method where are set the associations between role type and their behavior

public abstract class BaseBehavior
{
    public bool CanEdit { get; protected set; }
    public bool CanSubmit { get; protected set; }
    public bool CanReject { get; protected set; }
    public bool CanPublish { get; protected set; }

    public static BaseBehavior GetBehavior(RoleType type)
    {
        switch(type)
        {
            case RoleType.Writer:
                return new WriterBehavior();

            case RoleType.Editor:
                return new EditorBehavior();

            default:
                return new UserBehavior();
        }
    }
}

And finally here’s the class diagram. Program represents the client application that will use the BaseBehavior object

Strategy Pattern Class Diagram

Using the code

Assuming that you have a method called SetVisibility():

private void SetVisibility(RoleType CurrentRole)
{
    var behavior = BaseBehavior.GetBehavior(CurrentRole);

    btEditPost.Visible = behavior.CanEdit;
    btNewPost.Visible = behavior.CanEdit;
    btPublishPost.Visible = behavior.CanPublish;
    btRejectPost.Visible = behavior.CanReject;
    btSubmitPost.Visible = behavior.CanSubmit;
}

It can’t get easier than this :)

User Role - No actions allowed

Writer Role - Can create or edit posts, and submit them for approval

Editor Role - can publish or reject submited posts

See some screenshots of the demo application above.

References

Strategy Pattern (Wikipedia)
http://en.wikipedia.org/wiki/Strategy_pattern

Strategy Pattern using C#
http://www.dofactory.com/Patterns/PatternStrategy.aspx

Downloads

Download the demo code: StrategyPatternUI – VS2008

Happy coding!


Shout it


kick it on DotNetKicks.com

About these ads

14 thoughts on “Improve your UI code with Strategy Pattern

  1. IF one more role your system needs in future, then your GetBehavior method Should need a modification of BaseBehavior class which violates OCP(Open Closed Principle)…
    We can use reflection, and get rid of switch statements completely without violating OCP.

    Happy Coding!

    • Hi Ibrahim,

      IMO reflection adds unnecessary complexity. You still need to associate the new role with a particular behaviour somewhere, where would you do it?

      Quoting Uncle Bob Martin on the OCP:

      “It should be easy to change the behavior of a module without changing the source code of that module. This doesn’t mean you will never change the source code (…). What it means is that you should strive to get your code into a position such that, when behavior changes in expected ways, you don’t have to make sweeping changes to all the modules of the system. Ideally, you will be able to add the new behavior by adding new code, and changing little or no old code.”

      Source:
      http://blog.8thlight.com/uncle-bob/2013/03/08/AnOpenAndClosedCase.html

  2. Pingback: TapaGeuR » ITGIF – “IT-God” It’s Friday #24

  3. Regarding the “not a fan of extension methods” point. You can certainly achieve the same without using extensions. That was the original implementation you suggested. If you insist on using enums, I would use the same statically-initiallized dictionary technique in some other static/immutable class. This will allow you to get rid of the switch/case statements

  4. Rui:

    Q: Will your code be easier to read and/or maintain using extension methods?
    A: Yes. You can eliminate the switch case statements all together in the BaseBehavior class. Right now, the behavior violates the Open Closed principle. Open for change, closed for modification. Meaning if you add a new behavior, you’re going to have to change your base class. If there were other classes inheriting from BaseBehavior, those classes might experience ripple effects if BaseBehavior were to be modified.
    I would try the following:
    1) remove the getBehavior method from the BaseBehavior class and move it to the RoleType enum via an extension method. Logically, the RoleType should know what behavior it can perform
    2) move definition of what behavior a role is associated with to the RoleType extension class
    //Personally I’d prefer an interface here instead of an abstract class unless you truly want to default some behavior in the abstract class
    private static readonly Dictionary behaviorMap = new Dictionary
    {
    {RoleType.Editor, new EditorBehavior()},
    {RoleType.Writer, new WriterBehavior()},
    {RoleType.User, new UserBehavior()}
    };
    3) Implement the getBehavior method in the RoleType extention class in the following way:

    private static BaseBehavior GetBehavior(RoleType type)
    {
    if (!behaviorMap.ContainsKey(type))
    return rbehaviorMap[RoleType.User];

    return behaviorMap[type];
    }

    // so what you’ve done is removed all the fragile switch/case logic

    Q:Will you have the same level of abstraction?
    A: Yes. Your client code will have 0 if/else or switch/case statements to figure out what to do when you encounter a certain role type. The roleType already knows what behavior it is provisioned with. You’ll be able to do something like RoleType.getBehavior().canEdit().

    Q:Could you easily add new behaviors or change them without changing the client application? See:
    private void SetVisibility(RoleType CurrentRole)

    A: Yes. All you have to do is
    1) alter the RoleType enum – e.g. add a new enum member (e.g. RoleType.SearchEngineBot)
    2) add a new Behavior class which specifies certain behavior (e.g. SearchEngineBotBehavior)
    3) add another line to the extension class and add it to the dictionary -
    {RoleType.SearchBot, new SearchBehavior()}
    //the client is totally unaware of this change. and no if/else/switch/case statements had to be altered anywhere.

    The SetBehavior method remains exactly the same:
    private void SetVisibility(RoleType CurrentRole)
    {
    var behavior = CurrentRole.GetBehavior();

    btEditPost.Visible = behavior.CanEdit;
    btNewPost.Visible = behavior.CanEdit;
    btPublishPost.Visible = behavior.CanPublish;
    btRejectPost.Visible = behavior.CanReject;
    btSubmitPost.Visible = behavior.CanSubmit;
    }

    • Ok ok, all I needed was some code to see your “perspective”. Now it’s perfectly clear to me :)

      I really like your implementation, it’s very easy to understand and to maintain the code – I love the Dictionary trick, I never thought about it before.

      We are constantly leaning :D

      Thank you

    • Hi Lev, I’m not sure if I understand how you would implement this pattern using extension methods, could you please clarify?

      Some questions:
      Will your code be easier to read and/or maintain using extension methods?
      Will you have the same level of abstraction? Could you easily add new behaviors or change them without changing the client application? See:

      private void SetVisibility(RoleType CurrentRole)

      BTW extension methods are not compatible with .NET 2.0 (believe me, there are many people out there that still use it…. maybe even .NET 1.1).

      I confess that I’m not the biggest fan of extension methods, usually I use them when I want to extend types that I don’t own such as IQueryable or strongly-typed lambda expressions.

  5. Pingback: DotNetShoutout

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