Das Argument "Lesbarkeit" hat ja immer etwas mit Erfahrung zu tun. Wer an lambda expressions oder Continuations nicht gewöhnt ist, findet die erstmal schlechter lesbar. Das ist mit jedem Pattern so.
Die Frage ist also, warum sollte sich jemand umgewöhnen?
Argument 1: Das SRP ist nur in Variante 2 konsequent eingehalten. In Variante 1 hat Foo() zwei (2) Verantwortlichkeiten: 1. eine Entscheidung vornehmen und 2. weitere Handlungen zu einem Ganzen zu integrieren.
Argument 2: Es ist natürlich eine Illusion, Funktionseinheiten "für immer" gegen Veränderungen abschließen zu können. Für gewisse erwartbare Veränderungen kann man "Erweiterungshaken" anbringen (Strategy Pattern), aber irgendwann kommt es dann halt doch anders.
Wo jedoch konsequent das IOSP angewandt wird, da sind Veränderungen gar nicht mehr so gefahrvoll. Da versucht man nämlich erstmal, ein neues Feature dadurch herzustellen, dass man in eine Integration einen weiteren Aufruf einfädelt. Das ist eine Veränderung - aber eine triviale.
Der aufwändige Teil, der nun aber ungefährlich ist, besteht dann darin, eine ganz neue Funktionseinheit zu entwickelt, nämlich die eingefädelte.
IOSP + PoMO dienen also unmittelbar dem OCP.
Argument 3: Indem man die Entscheidung in eine Methode verlagert, wird einer domänenspezifischen Sprache eine Vokabel hinzugefügt. Die kann in anderen zusammenhängen wiederverwendet werden. Mit der zweiten Evaluate() Methode ist das ganze Thema Entscheidung erstens gekapselt und zweitens unabhängig vom Kontext.
Version 1:
if (Evaluate()) DoSomething();
Version 2:
Evaluate2(DoSomething);
Version 3:
ValidateB(); // mit Version 1
Bei Version 1 ist das "Thema" (Validation) in 3 "Aufrufe" verpackt: if + Evaluate() + DoSomething(). Außerdem ist klar sichtbar, wie entschieden wird: eben mit 1 if.
Wenn man das Thema woanders wieder hat, dann muss man alle kopieren.
Bei Version 2 sind es nur 2 "Aufrufe". Und Evaluate2() verpackt den das ganze Wie. Heute mag das nur 1 if sein, morgen aber vielleicht geschachtelte if oder irgendwas anderes.
Bei Version 3 gibt es zwar nur 1 "Aufruf" - aber der schafft eine Einheit aus Prüfung und Handlung. Das ist nicht schlecht; es entsteht eine Vokabel auf noch höherer Abstraktionsebene, die auch wiederverwendet werden kann. Das eigentliche Problem ist damit ja aber nur vertagt. Wie sieht es in ValidateB() aus?
"Aufwand" ist eine Continuation nur für den Ungeübten. Die Lesbarkeit ist - wie bei Kontrollanweisungen - nur bei tiefer Schachtelung schlecht.
Den vielleicht etwas höheren Testaufwand mit Continuation halte ich im Lichte der Vorteile für vernachlässigbar. Auch der folgt einem Muster, an das man sich schnell gewöhnt.
Es geht also nicht um Prinzipienreiterei.
Aber nicht jeder kann für sich die obigen Vorteile annehmen. Zumindest nicht sofort. Dann muss man auch mal aufhören zu überzeugen - und es stattdessen einfach tun. Mit Fundamentalisten muss man nicht diskutieren :-) Stattdessen an den eigenen Spaß denken und einfach so arbeiten, wie es einem leichter fällt.