Sollte jedes Objekt wissen, wie man sich präsentiert / zeichnet?

8

David West schlug in seinem Buch Object Thinking (Kapitel 10, Abschnitt 1, Unterabschnitt 2) vor, dass in einer idealen OO-Umgebung jedes Objekt in der Lage sein sollte, sich auf Anfrage zu präsentieren. sei es für Menschen (als GUI), nicht native Komponenten (als JSON und / oder XML) oder andere interessierte Parteien:

Objektdenken besagt, dass eine Ansicht (manchmal als Schnittstelle bezeichnet) - grafisch oder auf andere Weise - ein Mittel für ein Objekt ist, um mit einem anderen Objekt zu kommunizieren, und nicht mehr. Die Notwendigkeit einer Ansicht entsteht, wenn sich ein Objekt einem anderen Objekt (normalerweise einem Menschen) oder einer Anwendung (z. B. einer XML-Ansicht für Datenobjekte, die plattformübergreifend gemeinsam genutzt werden) in einer „nicht nativen“ Form präsentieren muss.

Die Ermittlung des Bedarfs und der Parameter, die von einer Ansicht erfüllt werden müssen, zeigt sich in den Szenarien, an denen das Objekt teilnimmt. Wenn ein Objekt aufgefordert wird, sich selbst anzuzeigen, muss es eine Ansicht verwenden - eine Darstellung -, die für den Absender dieser Anzeigemeldung geeignet ist. Wenn beispielsweise ein Objekt versucht, sich selbst zu instanziieren (einen Wert für sich selbst zu erhalten), muss es einem Menschen (oder einem anderen dienstleistenden Objekt) eine Ansicht von sich selbst als implizite Anforderung für einen Wert präsentieren. Wenn wir eine GUI erstellen, die als Vermittler zwischen einem Softwareobjekt und einem menschlichen Objekt dient, verwenden wir Glyphen für Anzeigezwecke und Widgets für Interaktionszwecke.

Aber welche Glyphen und Widgets müssen in die GUI aufgenommen werden? Nur diejenigen, die erforderlich sind, um das Szenario oder die Szenarien 4 von unmittelbarem Interesse abzuschließen, während die Anwendung ausgeführt wird. Diese Perspektive ist für die meisten Entwickler nicht intuitiv, da sie vorschlägt, eine GUI aus der Anwendung heraus zu definieren.

Betrachten Sie als Beispiel eine Brauerei. Auf der einen Seite stehen mit Bier gefüllte Bottiche. An der komplexen Produktionslinie bestehend aus Flaschenwaschanlagen, Füllstationen, Verschließmaschinen und Verpackungsmonteuren. Darüber hinaus gibt es eine Kontrollstation, die die Brauerei überwacht und menschliche Manager über Status und Probleme informiert. Traditionelle Entwickler beginnen wahrscheinlich mit der Analyse und dem Entwurf eines „Brauereimanagementsystems“ aus Sicht des Control Panels. Dies ist analog zum Entwerfen über die Schnittstelle in.

Objektdenken würde stattdessen darauf hindeuten, dass Sie überlegen, welches Objekt der Hauptkunde der Brauerei und all ihrer unzähligen Maschinen ist. In wessen Auftrag existiert das komplexe Labyrinth der Ausrüstung? Die richtige Geschäftsantwort lautet natürlich "Der Kunde". Eine Antwort, die das Denken von Objekten besser widerspiegelt, lautet: „Das Bier.“ Alle Szenarien werden aus der Perspektive des Bieres geschrieben und versuchen, sich in eine Flasche mit einem Verschluss zu packen, der in einem Paket platziert ist und in einem Lastwagen wohnt. Das Bedienfeld ist ein passiver Beobachter 5 des Zustands der Brauerei. Wenn das Bier irgendwann auf ein Problem stößt, liegt es in der Verantwortung des Bieres, die Intervention der menschlichen Bediener anzufordern, indem eine Nachricht an das Bedienfeld (oder an maschinenspezifische Bedienfelder) gesendet wird, in der ein Interventionsdienst angefordert wird.

Diese Perspektive vereinfacht das GUI-Design und beseitigt, was noch wichtiger ist, die Vielzahl von Manager- und Controller-Objekten, die beim Entwerfen aus der Perspektive des Control Panels (GUI) unvermeidlich auftreten.

Von einem Anfänger in der OO-Welt kommend: Sollte das wirklich der Fall sein?

Objekte zu haben, die wissen, wie man sich selbst darstellt, könnte sicherlich die Anzahl der Controller- / Manager-Objekte verringern, die West in seinem Buch wiederholt sagte, ein Objektdenker sollte angeblich versuchen, dies um jeden Preis zu vermeiden. Aber wird die Einhaltung dieser "Regel" nicht gegen SRP verstoßen ?

Auch (wenn sich herausstellt, dass dies der Fall ist), bei einer typischen Implementierung beispielsweise in einer Android-Anwendung: Wie kann man diese Art von Ziel erreichen? Sollte jedes Objekt, das wir erstellen, wissen, wie man sich als präsentiert View?

MrHadiSatrio
quelle
3
SRP bedeutet nicht, was Sie denken, dass es bedeutet. SRP bedeutet, dass Ihr "Auto" -Objekt keine Haustierprobleme diagnostiziert. Dies bedeutet nicht, dass ein visuelles UI-Element nicht in der Lage sein sollte, sich selbst anzuzeigen.
Robert Harvey
Aha. Sie erwähnen jedoch das visuelle UI-Element . Wenn wir diese Regel beim Entwerfen unserer Software anwenden, werden dann nicht die meisten Objekte, die wir erstellen, visuelle Elemente der Benutzeroberfläche sein ? Weil die meisten von ihnen früher oder später eine Interaktion mit dem Benutzer verlangen, oder?
MrHadiSatrio
1
@RobertHarvey Ich bin mir nicht sicher, wie dieses Zitat ein MVC-Muster unterstützen könnte. Es liest sich so, als ob es in der Verantwortung der Klasse liegt, ihre Schnittstelle / "Ansicht" zu definieren, um ihre Anforderungen zu erfüllen, während das Modell in einem MVC-Muster die Ansicht, in der es angezeigt wird, nicht kennt.
Ben Aaronson
1
@ridsatrio Da Sie ein selbst eingestandener Anfänger sind ... Ich schlage vor, dass Sie sich bemühen, Schnittstellen zu schreiben, die existieren, um ein Objekt über etwas zu informieren, das außerhalb seiner Kontrolle passiert ist, anstatt Methoden, die Objekte anweisen, Dinge zu tun. Methoden wie "buttonWasClicked" oder "pageWillBeDisplayed" sind also besser als "changeState" oder "drawInCorner". "Sagen Sie nicht fragen ..." Erzählen Sie Objekten, was passiert, anstatt sie zu bitten, Dinge zu tun.
Daniel T.
2
Der Autor hätte irgendwann aufhören sollen zu schreiben und gedacht: "Möchte ich den Leuten tatsächlich etwas über OOP beibringen, indem ich über Bier spreche, das in einer Flasche sein will, und den Betreibern sagt, wann es nicht kann?" Ich verstehe nicht, wie dies irgendwelche Konzepte oder Ideen für irgendjemanden beleuchten soll.
Sebastian Redl

Antworten:

12

Ich denke, dies ist eines der am schwersten zu verstehenden Dinge über OO-Design und ehrlich gesagt denke ich, dass viele Autoren falsch liegen und / oder es nicht sehr gut erklären. Viele Leute verstehen das falsch und finden es nie wirklich heraus. Nehmen wir ein Beispiel, das nicht auf der GUI basiert, sondern auf dieselbe Gefahr stößt.

In Java hat jedes Objekt eine Methode gleich. Sie haben dann Sammlungstypen wie Set und Map, die von dieser Methode abhängen, um zu bestimmen, wann Objekte zur Sammlung hinzugefügt werden sollen oder wann sie doppelt vorhanden sind. Dies scheint vielen Leuten eine gute OO zu sein. Das Problem ist, dass Sie am Ende ein Objekt (die Sammlung) haben, dessen Verhalten nicht von ihm bestimmt wird, sondern von den darin enthaltenen Objekten. Dies ist ein bisschen so, als würden die Passagiere im Bus direkt dorthin fahren, wo sie hin sollen. Was ist, wenn sie nicht übereinstimmen? Dies ist kein theoretisches Problem, sondern ein wirklich heikles Problem, bei dem Sie die Vererbung grundsätzlich aufheben müssen, um Fehler in Ihrem Programm zu vermeiden. Nimm eine Form und eine farbige Form. Entspricht ein 2x2-Quadrat einem 2x2-blauen Quadrat? Shape sagt "Ja" und ColoredShape sagt "Nein". WHO' ist richtig? Die Antwort hängt davon ab, was in Ihrer Sammlung geschehen soll. Es kann auch nicht davon abhängen, was Sie versuchen zu tun.

Sie werden feststellen, dass dies immer wieder als Problem auftritt. Das Lustige ist, dass es eine Lösung gibt und sie gleich nebenan im Comparable ist. Objekte, die Comparable implementieren, haben dasselbe Rätsel, aber jetzt müssen sie nicht nur feststellen, ob sie gleich sind, sondern auch, ob sie größer als ein anderes Objekt sind. Außerhalb eines sehr engen Anwendungsbereichs ist es wirklich unlösbar. Wir haben also dieses andere Ding namens Komparator. Es ist Aufgabe, zwei Objekte zu betrachten und der Sammlung mitzuteilen, welches größer ist. Alle Probleme, die Sie im vergleichbaren Objekt haben, verschwinden.

Ich kenne dieses Buch nicht und kenne den Autor nicht, aber das Beispiel mit dem Bier scheint überhaupt nicht hilfreich zu sein. Wie würde das Bier wissen, ob es in einer Flasche oder in einem Fass sein sollte und warum sollte es diese Entscheidung treffen? Es ist Aufgabe, gut zu schmecken und Alkohol in den Blutkreislauf der Benutzer zu bringen. Denken wir wirklich, dass Brauereien so funktionieren? "OK Bier, solltest du in einer Flasche oder in einem Fass sein und wenn es eine Flasche ist, sollte es eine 25 Unzen Flasche oder eine 12 Unzen Flasche sein?" Was ist das Bier in diesem Fall (kein Wortspiel beabsichtigt) überhaupt? Ist es ein Tropfen Bier? Vielleicht ist dies nicht im Zusammenhang, aber ich denke, das macht es falsch oder zumindest fügt es diesem Konzept keine Beleuchtung hinzu.

Abgesehen davon gibt es einen Ansatz zum Erstellen von Schnittstellen, den ich verwendet habe, der die Dinge vereinfachen und die OO verbessern kann. Im Wesentlichen erstellen Sie eine Schnittstelle, die die abstrakten Aktionen definiert, die Sie zum Anzeigen des Objekts ausführen können. Möglicherweise haben Sie eine Schnittstelle namens DisplayMethoden wie setTitleoder setDescriptionwenn Sie das Standard-Java-Namensmuster verwenden. Dann hätte Ihr Objekt eine Methodedisplay(Display display)(weil dreimal der Reiz ist!) Bei diesem Ansatz muss das Objekt nicht verstehen, was die Schnittstelle ist, es kann Text, Binär, SVG, Bitmap sein, was auch immer, und die Schnittstelle muss nichts über das Objekt wissen . Auf diese Weise kann sich ein Objekt "selbst anzeigen", ohne wissen zu müssen, wie die Anzeige funktioniert. Dieser Ansatz kann die Anzahl der benötigten Wrapper-Klassen erheblich reduzieren, kann jedoch umständlich sein, wenn Sie komplexe Anzeigeanforderungen haben, die je nach Objekt variieren. Sie können es mit Standardansätzen vom Typ MVC mischen, um eine gute Wirkung zu erzielen.

JimmyJames
quelle
2
Schöne Antwort, und ich denke, sie berührt alle relevanten Themen.
Robert Harvey
Dies ist in der Tat eine sehr schöne Antwort. Denken Sie darüber nach, vielleicht ist Ihre Art, Objekten das Zeichnen über eine definierte Schnittstelle zu ermöglichen, der beste Ansatz für diese Angelegenheit. Auf diese Weise Objekte halten nach wie vor ihr Recht auf Kontrolle , wie sie (nicht von einem externen Controller) angezeigt werden soll , aber ohne sie müssen lernen , wie ein Displayin seiner konkreten Umsetzung funktionieren würde (wie sollten sie waren sie eine Ebene gegeben werden JFrame, zum Beispiel ). Vielen Dank.
MrHadiSatrio
1
Diese Antwort ist großartig und lässt mich viel über OOP im Allgemeinen nachdenken. Ich habe festgestellt, dass ein ECS so viel einfacher zu warten ist, dass es Daten und Funktionen voneinander trennt, und teilweise, weil es nicht unter der Analogie leidet, die Sie bei der Verwendung von Objekten beschrieben haben, die versuchen, intern zu bestimmen, mit welchem ​​Verhalten sie sich vergleichen können etwas anderes.
8

Das Prinzip der Einzelverantwortung bedeutet nicht, dass eine Klasse nur eines tut. Dies bedeutet, dass eine Klasse einen einzigen Grund hat, sich zu ändern.

Sie denken wahrscheinlich an eine Methode , die wirklich nur eines tut.

Aus logischer Sicht würde Ihre Version von SRP bedeuten, dass Sie niemals etwas protokollieren können, da die Protokollierung in einer separaten Verantwortung liegt.

Es ist besser, sich eine Klasse als ein einzelnes, genau definiertes Fach vorzustellen. Sie können verschiedene Methoden verwenden, die dieses Thema unterstützen, und alle können unterschiedliche Aufgaben ausführen.

Die grundlegendste "Display Me" -Methode ist ToString, die immer eine Methode für das Objekt ist.


Wenn wir eine Benutzeroberfläche erstellen, fördern wir in der Regel die Trennung von Bedenken, indem wir Objekte bereitstellen, deren einziger Zweck darin besteht, Daten von anderen Objekten (z. B. Ansichten) anzuzeigen.

Vielleicht ist ein Beispiel angebracht. Betrachten Sie eine PHP-Website mit einer Ansicht. Eine einfache Ansicht könnte folgendermaßen aussehen:

<?php
class View
{
    private $model;
    private $controller;

    public function __construct($controller,$model) {
        $this->controller = $controller;
        $this->model = $model;
    }

    public function output(){
        return "<p>" . $this->model->string . "</p>";
    }
}

In PHP enthältoutput() die Ansicht immer eine Funktion. Um die visuelle Darstellung einer Ansicht zu erhalten, müssen Sie lediglich aufrufen output(), und Sie erhalten eine Zeichenfolge, die für die Anzeige in jedem modernen Browser geeignet ist.

Wenn Sie bemerken, verweist die Ansicht auf ein Objekt namens model. Dies ist das Objekt, das die tatsächlichen Daten enthält. Die Ansicht und das Modell befinden sich in separaten Objekten. Dies ist es, was die Trennung von Bedenken begründet.

Die Trennung von Bedenken ist für Websites wichtig, da ein Designer damit neben dem Programmierer an einem Webseiten-Design arbeiten kann .

Weiterführende Literatur
Das MVC-Muster und PHP

Robert Harvey
quelle
In Ordung. Aber wenn wir die Ansicht vom Modell getrennt haben, ist es dann immer noch die Aufgabe des Modells, die Ansicht bereitzustellen? Denn genau das erhalte ich aus dem obigen Zitat: Das Objekt (oder Modell in Ihrem Wortschatz) sollte wissen, wie es sich selbst anzeigt, oder? Angenommen, Sie haben ein ReceiptObjekt in einer typischen POS-Software, das Sie immer noch aufrufen würden, Receipt.draw(Canvas)und nicht ReceiptView.draw(Receipt).
MrHadiSatrio
2
In MVC liegt es in der Verantwortung des Controllers , die zu verwendende Ansicht auszuwählen.
Robert Harvey
Aber Controller-Objekte sind genau das, was in der Wahrnehmung von West im Objektdenken (und damit in diesem Zitat) als Dinge zu vermeiden ist. Das Zitat besagt ausdrücklich, dass die ganze Idee hinter "Objekten, die wissen, wie man sich selbst anzeigt" darin besteht, "Manager- und Controller-Objekte" zu vermeiden.
MrHadiSatrio
Das ist in Ordnung, aber ich denke, Sie müssen dieses Denken auf Objekte beschränken, deren einziger Zweck die visuelle Darstellung ist. Ansichten, mit anderen Worten. Dem Controller ist es egal, wie die Ansicht sich selbst anzeigt. Es ist nur wichtig, welche Ansicht verwendet werden soll. Außerdem ist MVC nicht das einzig mögliche Anzeigeparadigma, und andere (insbesondere MVVM) arbeiten etwas anders. Das Grundprinzip der Trennung von Bedenken bleibt jedoch bestehen.
Robert Harvey
Beachten Sie, dass das Buch , das Sie lesen ist ziemlich alt für ein Software - Buch (2004). MVC und MVVM waren noch nicht allgemein gebräuchlich.
Robert Harvey
1

Nach den von Ihnen eingefügten Zitaten zu urteilen, interpretieren Sie den Text falsch.

Der Autor sagt nicht, dass jedes Objekt in der Lage sein sollte, sich in einer Benutzeroberfläche zu präsentieren. Dies wäre unmöglich, da ein Objekt nicht wissen kann, in welcher Benutzeroberfläche es angezeigt wird (in einer WinForms-App, einer Linux-App, die XServer als JSON-Zeichenfolge, als XML, als PNG-Image usw. verwendet).

Der Punkt ist, dass Sie spezielle Ansichten schreiben sollten, deren alleinige Verantwortung darin besteht, eine bestimmte Entität anzuzeigen. Sie können beispielsweise eine Ansicht schreiben, die ein Objekt als HTML rendert (wie dies bei Ansichten in MVC-Anwendungen der Fall ist). Sie können einen JSON-Serializer erstellen, der ein Objekt in eine JSON-Zeichenfolge verwandeln kann. Sie können ein Objekt erstellen, das andere Arten von Objekten in PDF-Berichte umwandelt. Es hängt alles ab.

Der Punkt ist, die Geschäftseinheit von der visuellen (oder serialisierten) Darstellung zu trennen. Sie sind verschiedene Dinge und ändern sich aus verschiedenen Gründen.

Sara
quelle
Ich habe meine Frage bearbeitet, um das Zitat zu erläutern.
MrHadiSatrio
1
Obwohl ich zugebe, dass meine Antwort nicht mehr ganz so relevant ist, sehe ich nicht, was Ihre Frage mit dem Zitat zu tun hat. Das Zitat scheint eher von APIs und Schnittstellen als von visuellem Rendering zu sprechen. Auf welche Teile eines Objekts sollte zugegriffen werden können und welche Nachrichten kann es senden, damit es seinen Job in der Geschäftsdomäne abschließt?
Sara
"Wenn wir eine GUI erstellen, die als Vermittler zwischen einem Softwareobjekt und einem menschlichen Objekt dient, verwenden wir Glyphen für Anzeigezwecke und Widgets für Interaktionszwecke." Nach diesem Satz zu urteilen, bin ich mir ziemlich sicher, dass das Zitat auch visuelle Wiedergabezwecke impliziert.
MrHadiSatrio
Es gibt dort nichts, was besagt, dass "das fragliche Objekt auswählen sollte, welche Glyphen und Widgets es für einen bestimmten Kontext am besten darstellen, und auch für das Rendern dieser Glyphen und Widgets verantwortlich sein sollte." Das Objekt und das Objekt, das es anzeigt, müssen nicht unbedingt dasselbe sein (sollten es auch nicht sein).
Sara