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

Parcel – module bundler, który da się lubić... Parcel to narzędzie które wnosi nową jakość na zdominowany przez Webpacka rynek module bundlerów. Czy dwa podstawowe założenia o których mówi doku...
Pasja kontra Profesjonalizm Jak wyobrażasz sobie programistę który odnosi sukcesy? Czy to pasjonat który lubi to co robi, czy profesjonalista skupiony na wyniku swojej pracy? A...
Sposoby na motywację do nauki programowania i posz... Chciałbym podzielić się dziś z Tobą refleksją na temat motywacji do nauki programowania. Temat ten oczywiście nie dotyczy wyłącznie osób początkuj...
Aplikacje mobilne – porównanie technologii Załóżmy, że stoi przed nami zadanie wykonania aplikacji mobilnej. Klient nalega oczywiście, żeby zrobić to szybko, dobrze i tanio. Jak podejdziemy do ...