2

I am still learning Design Patterns and I have a situation in my hand. I am developing a simple employee management Python program.

An employee can be a Developer, Senior Developer, Lead Developer, Manager. Now during the tenure employee may get promoted and thus a responsibility change happens with same employee.

I thought of using Strategy Pattern, as during runtime employee will be promoted and thus require a new algorithm to describe his responsibilities.

The below image clarifies more of what I implemented.

UML Diagram

Role:RoleStrategy is a composition in Employee class. However, since responsibility of each strategy would be different, the operations/methods of each class would be different, which kind of breaks this pattern, I believe. Employee class would have to take care of different things at different role.

I thought of using State Design Pattern too as internal state of employee changes at each promotion.

I am bit confused here now. Please help!

  • What happens when an employee is promoted? Changing his/her title or just role ? – Engineert Mar 8 at 14:49
  • Employee role change would happen as other personal details would remain same. Now Role would have to have different operations like manage employee, manage project etc – Avij Mar 8 at 14:53
  • 1
    Strategy pattern is more about changing strategy to calculate same thing by different approaches. For example you can calculate altitude many ways. I recommend you to define role-right relations. By using this way, you can determine easily which role has which right(s). Beyond, it is easy to extend. You can define rights on database or can create a method/class for each right. – Engineert Mar 8 at 15:40
  • @Engineert So you are suggesting more like a decorator pattern, where access rights can define which methods can an employee have access to. – Avij Mar 9 at 3:06
3

operations/methods of each class would be different, which kind of breaks pattern I believe

Yes and no.

It depends on how reasonable it is for every employee to implement, say, a manage() method. Those who are not managers would implement this method by doing nothing at all.

Look up the Null Object Pattern. It's my favorite pattern. It talks about how you can feed valid types to complex systems that demand methods be implemented, but implements them by quietly doing nothing when called.

You could make the strategy pattern fit this problem using null methods that quietly do nothing when called.

The problem you run into is doing this over and over every time a new method is required forces you to edit everything in the strategy. This trick works better when you're adding types that need fewer methods. It doesn't work that well when adding types that need more methods.

A different pattern would be composition and delegation. Here you don't add methods to an existing type. You create a new type with all the methods needed now. Where that includes old methods you can implement them by delegating to implementations of the old type.

Design from the point of view of the using code. What does the code that uses a manager need that manager to do? What messages are sent to a manager? Let the manager expose methods that support those messages. Any that duplicate messages that are sent to an employee can be delegated to an employee object that the manager holds. That way you don't duplicate that code. You can go so far as to implement an employee interface to cover this role if the manager needs to be viable to be added to lists of employees that will all be treated as simply employees.

But the situation where the Strategy pattern truly shines is where the methods are all the same for every implementation and abstract enough that none of them reveal which implementation is hiding under the hood. So rather than manage() it would be things like reportPerformance(). A typical employee would only report their own performance. A manager would report their own as well as those they manage.

When you choose abstract names for your methods you support the hiding of these different types from the using code. That way the using code doesn't have to know which implementation they have. They can use them all interchangeably. That's polymorphism. It's powerful. It's a fair bit of work but it can help keep code changes from spreading so you can add new ideas by making the change in one place.

  • Thanks for such an elaborated explanation. Yes, using NULL methods Strategy can work, as on other hand new feature addition may get difficult to manage. Yes, composition and delegation may work. The problem i initially ran into was Employee instance should not to be re-created when promotion happens. It means that employee can variably change their role. If i choose Role as Strategy Pattern and composite its Allowed Operations as Template pattern (as employee have common methods, check leave, checkperformance) it can help, but client of EMP class need to know operations before hand – Avij Mar 9 at 3:20
0

In a comment above you mentioned operations like "manage projects" or "manage employees".

I doubt in a real world program one would to have methods like "ManageProjects" or "ManageEmployees" in these individual strategy classes. The former are high level operations which require a component or program, not a single method. However, these high-level operations require low-level functions from the strategy object which make perfectly sense for all subclasses of RoleStrategy.

For example, a RoleStrategy class could provide boolean methods like CanManageProjects() or CanManageEmployees(). These are methods which may deliver always "true" for a manager, and "true" or "false" determined by a different "algorithm" for a developer, or maybe always "false". But the important part here is, they can be placed in RoleStrategy as virtual methods and overriden in the subclasses.

There will be some decision-making code then at another place in your program which calls CanManageProjects(), and start the high-level "manage projects" operations only if the result is "true".

So, yes, the strategy pattern can be perfectly applicable here. If you encounter another operation where you are unsure about, then make a try to implement it, show us where you got stuck, and then we can discuss it. Currently, I don't see any methods in the Strategy part of your UML diagram - without those, there is only a "vague notion of a problem", not a real problem to solve, which makes it hard to give you a better answer.

  • i do agree with it. Will provide some concrete impl here – Avij Mar 10 at 3:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.