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.