Ich habe mich gefragt, was den Iterator im Vergleich zu anderen ähnlichen Konstrukten so besonders macht, und das hat die Viererbande dazu gebracht, ihn als Entwurfsmuster aufzulisten.
Der Iterator basiert auf Polymorphismus (einer Hierarchie von Sammlungen mit einer gemeinsamen Schnittstelle) und der Trennung von Bedenken (das Durchlaufen der Sammlungen sollte unabhängig von der Art und Weise sein, wie die Daten strukturiert sind).
Was aber, wenn wir die Hierarchie von Sammlungen beispielsweise durch eine Hierarchie mathematischer Objekte (Ganzzahl, Gleitkomma, Komplex, Matrix usw.) und den Iterator durch eine Klasse ersetzen, die einige verwandte Operationen für diese Objekte darstellt, z. B. Potenzfunktionen. Das Klassendiagramm wäre das gleiche.
Wir könnten wahrscheinlich viele weitere ähnliche Beispiele wie Writer, Painter, Encoder und wahrscheinlich bessere finden, die auf die gleiche Weise funktionieren. Ich habe jedoch noch nie gehört, dass eines davon als Design Pattern bezeichnet wird.
Was macht den Iterator so besonders?
Ist es die Tatsache, dass es komplizierter ist, weil es einen veränderlichen Zustand zum Speichern der aktuellen Position innerhalb der Sammlung erfordert? Aber dann wird ein veränderlicher Zustand normalerweise nicht als wünschenswert angesehen.
Lassen Sie mich zur Verdeutlichung meines Punktes ein detaillierteres Beispiel geben.
Hier ist unser Designproblem:
Angenommen, wir haben eine Hierarchie von Klassen und eine Operation, die für die Objekte dieser Klassen definiert ist. Die Schnittstelle dieser Operation ist für jede Klasse gleich, die Implementierungen können jedoch völlig unterschiedlich sein. Es wird auch angenommen, dass es sinnvoll ist, die Operation mehrmals auf dasselbe Objekt anzuwenden, beispielsweise mit unterschiedlichen Parametern.
Hier ist eine sinnvolle Lösung für unser Entwurfsproblem (praktisch eine Verallgemeinerung des Iteratormusters):
Zur Trennung von Bedenken sollten die Implementierungen der Operation nicht als Funktionen zur ursprünglichen Klassenhierarchie (Operandenobjekte) hinzugefügt werden. Da wir die Operation mehrmals auf denselben Operanden anwenden möchten, sollte sie durch ein Objekt dargestellt werden, das einen Verweis auf den Operanden enthält, nicht nur durch eine Funktion. Daher sollte das Operandenobjekt eine Funktion bereitstellen, die das Objekt zurückgibt, das die Operation darstellt. Dieses Objekt bietet eine Funktion, die die eigentliche Operation ausführt.
Ein Beispiel:
Es gibt eine Basisklasse oder Schnittstelle MathObject
(dummer Name, ich weiß, vielleicht hat jemand eine bessere Idee.) Mit abgeleiteten Klassen MyInteger
und MyMatrix
. Für jede sollte MathObject
eine Operation Power
definiert werden, die die Berechnung von Quadrat, Würfel usw. ermöglicht. Also könnten wir schreiben (in Java):
MathObject i = new MyInteger(5);
Power powerOfFive = i.getPower();
MyInteger square = powerOfFive.calculate(2); // should return 25
MyInteger cube = powerOfFive.calculate(3); // should return 125