Strategy design pattern - real life example

Strategy design pattern - real life example

Today I’ll show you a quite nice example of the Strategy pattern from a real project I was working on some time ago.

First, let’s check out a textbook definition of the Strategy pattern:

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

also let’s look at the UML class diagram:

 

przechwytywanie

 

Great. Everything clear. But, how to use this pattern in everyday work? I’ve got for you (I think) a great example. It’s code from the real project. Of course I had to change some names, but the structure of the code is untouched.

 

Ok, let’s dig in!

The project is about, let’s say, a consulting company. There are some consultants, managers and boss. Every consultant work with one or many groups of learners, additionally each consultant can be a leader of the group.. but stop! It’s not important! You don’t need to understand “business rules”. I’ll show you code before and after refactoring. I think the difference is really, really big and this is what you need to understand.

So, we were creating a new feature let’s call it “special groups” and we had to extend an AuthorizationHelper.

After few weeks our new permissions “algorithm” looked like this:

Ok, maybe this is not so bad.. But look also at extra GetOperationsPermissions method which we are using (at line 12) inside GetPermission_BeforeRefactoring method:

Right, now it’s so bad 😉

Now, let’s imagine that I’ve got a task to change sth. One little change. I don’t remember exactly what was it, but sth like this – “When a employee is in the manager role, he should have full access to the member description, but if the employee is not in the manager role, he should have only read access to this section. It shouldn’t takes you more than 5 minutes” – yep 😉

And we’ve got a problem. There is no easy way to do this. What’s more – there are no unit tests for the AuthorizationHelper. Change sth in this “bush” of if statements and what? Check all possible combinations of roles in application manually? Are you kidding me?

 

First – we create unit tests!:)

It’s not our today topic, so let’s say that unit tests are done.

 

Next – replace conditional logic with Strategy

As we saw, our method is responsible for permissions. There are few cases dependent on user role and IsLeader flag. In various combinations of this parameters we return different permissions, so our strategy interface looks like:

Next, we need to implement concrete strategies, each for every combination.

  • SpecialGroupsBossPermissionsProvider:

  • SpecialGroupsConsultantPermissionsProvider:

  • SpecialGroupsLeaderPermissionsProvider:

  • SpecialGroupsManagerPermissionsProvider:

  • SpecialGroupsDenyPermissionsProvider:

And finally our AuthorizationHelper:

But! There are still so many if statements! Ok, and what? There is nothing wrong with them. Compare code before refactoring and after. Isn’t it more clean? More readable? I think it is 🙂

 

Let’s sum it up!

After refactoring, we’ve got implemented Strategy pattern and our code fulfills SOLID rules:

  1. Single Responsibility Principle – we’ve got separated providers classes. Each class is responsible only for one thing (permissions for boss, for consultant, for manager – NOT FOR ALL AT ONCE).
  2. Open/Closed Principle – we don’t have to modify any of providers when we want to introduce another one. Just add new class without touching existing providers.
  3. Dependency Inversion Principle – it’s our ISpecialGrousPermissionsProvider. We depend on abstraction, not on specific implementation.

What about our previous task “When a employee is in the manager role, he should have full access to the member description, but if the employee is not in the manager role, he should have only read access to this section.”?

Yep, now it really took me 5 minutes. First I’ve opened SpecialGroupsMangerPermissionProvider and set access level for the member description operation to full. Next I’ve opened others providers and set access level for this operation to read-only. That’s all. In addition I was sure I didn’t break anything by the way.

Powiązane

Page Object, WebdriverIO advanced concepts –... Page Object pattern is well-known in the world of test automation. Fortunately the new version (v4) of webdriver.io test automation framework was ...
Getting started on ASP.NET Core & React ̵... Contents Episode 1 - Introduction Episode 2 - Backend / Infrastructure Episode 3 - Frontend Setup Episode 4 - Data flow (you are here)...
Trzy razy NIE, czyli co ci daje doświadczenie Każdego dnia staram się obserwować cały nasz świat programowania i wyciągać wnioski dotyczące tego, o co tak naprawdę tutaj chodzi. Po kilku latac...
Aplikacje mobilne – jak zacząć Zaczynając naukę programowania stoi przed Tobą wiele wyborów. Ten, który najbardziej wszystkich trapi to wybór języka programowania. Decyzja ta jest m...