So probably like many, I often find myself running into headaches with design problems in which, for example, there is some design pattern/approach that seems to intuitively fit the problem and has desired benefits. Very often there is some caveat which makes it difficult to implement the pattern/approach without some kind of work around which then negates the benefit of the pattern/approach. I can very easily end up iterating through many patterns/approaches because predictably almost all of them have some very significant caveats in real-world situations in which there simply isn't an easy solution.
Example:
I'll give you a hypothetical example based loosely on a real one I recently encountered. Let's say I want to use composition over inheritance because inheritance hierarchies have hindered the scaleability of the code in the past. I might refactor the code but then find that there are some contexts where the superclass/baseclass simply needs to call functionality on the subclass, despite attempts to avoid it.
The next best approach seems to be implementing a half delegate/observer pattern and half composition pattern so that the superclass can delegate behaviour or so that the subclass can observe superclass events. Then the class is less scaleable and maintainable because its unclear how it should be extended, also it is tricky to extend existing listeners/delegates. Also information isn't hidden well because one starts needing to know the implementation to see how to extend the superclass (unless you use comments very extensively).
So after this I might opt to simply just use observers or delegates completely to get away from the drawbacks that comes with mixing up the approaches to heavily. However this comes with its own problems. For example, I might find that I end up needing observers or delegates for an increasing amount of behaviours until I end up needing observers/delegates for practically every behaviour. One option could be to just have one big listener/delegate for all of the behaviour but then the implementing class ends up with lots of empty methods etc.
Then I might try another approach but there are just as many issues with that. Then the next one, and the one after etc.
This iterative process gets very difficult when each approach seems to have as many problems as any of the others and leads to a sort of design decision paralysis. It is also difficult to accept that the code will end up equally problematic regardless of which design pattern or approach is used. If I end up in this situation does it mean that the problem itself needs to be rethought? What do others do when they encounter this situation?
Edit: There seems to be a number of interpretations of the question that I want to clear up:
- I have taken OOP out of the question completely because it turns out that it is not actually specific to OOP, plus it is too easy to misinterpret some of the comments I made in passing about OOP.
- Some have claimed I should take an iterative approach and try different patterns, or that I should discard a pattern when it ceases to work. This is the process I intended to refer to in the first place. I thought this was clear from the example but I could have made it clearer, so I've edited the question to do so.