You wrote
I know the following is bad
and already here is a misconception: thinking religiously in terms of good and bad about this. My interpretation of Tell-Don't-Ask is: when you see a code snippet like
if(a.isX){
a.doY();
}
you may consider refactoring it to a.doYWhenX();
- or not. But before you decide about this refactoring, also check
whether
doYWhenX()
is a useful abstraction in your contextwhether
doYWhenX()
has some reuse potentialwhether it helps to make
a.isX
(ora.isX()
) privatewhether it makes the using code more readable
is it worth the hassle?
So my recommendation is to change your mindset about the "Tell-Don't-Ask principle" - it is a rough guideline, a rule-of-thumb design heuristic, nothing more.
Now apply this to your case with two objects:
if(a.isX && b.isP){
a.doY();
b.doQ();
}
Whether it it more suitable to refactor this
to
a.doYQWhenXP(b);
orto
b.doYQWhenXP(a);
orto
myService.doYQWhenXP(a,b)
, orleave the code as it is
depends heavily on the context: which variant in your real world context creates highest readability, best reusability, most sensible abstraction, or best encapsulation. Meaningless names like doX
or isP
alone are not suitable for making such a decision.