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!

Doc Brown
  • 218,378
Avij
  • 129

2 Answers2

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.

candied_orange
  • 119,268
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.

Doc Brown
  • 218,378