Das Prinzip des geringsten Wissens

32

Ich verstehe das Motiv hinter dem Prinzip des geringsten Wissens , finde aber einige Nachteile, wenn ich versuche, es in meinem Design anzuwenden.

Eines der Beispiele für dieses Prinzip (eigentlich, wie man es nicht verwendet), das ich im Buch Head First Design Patterns gefunden habe , besagt , dass es im Sinne dieses Prinzips falsch ist, eine Methode für Objekte aufzurufen, die vom Aufrufen anderer Methoden zurückgegeben wurden .

Aber es scheint, dass es manchmal sehr notwendig ist, solche Fähigkeiten zu nutzen.

Zum Beispiel: Ich habe mehrere Klassen: Video-Capture-Klasse, Encoder-Klasse, Streamer-Klasse und alle verwenden eine andere grundlegende Klasse, VideoFrame, und da sie miteinander interagieren, können sie zum Beispiel Folgendes tun:

streamer Klassencode

...
frame = encoder->WaitEncoderFrame()
frame->DoOrGetSomething();
....

Wie Sie sehen, wird dieses Prinzip hier nicht angewendet. Kann dieses Prinzip hier angewendet werden, oder ist es so, dass dieses Prinzip bei einem Entwurf wie diesem nicht immer angewendet werden kann?

ransh
quelle
Mögliches Duplikat der Verkettung
Mücke
4
Das ist wahrscheinlich ein genaueres Duplikat.
Robert Harvey
1
Verwandte: Handelt es sich bei einem Code wie diesem um ein „Zugunglück“ (Verstoß gegen das Gesetz von Demeter)? (vollständige Offenlegung: das ist meine eigene Frage)
ein Lebenslauf

Antworten:

21

Das Prinzip, von dem Sie sprechen (besser bekannt als Law of Demeter ) , kann angewendet werden, indem Sie Ihrer Streamer-Klasse eine weitere Hilfsmethode wie hinzufügen

  {
    frame = encoder->WaitEncoderFrame()
    DoOrGetSomethingForFrame(frame); 
    ...
  }

  void DoOrGetSomethingForFrame(Frame *frame)
  {
     frame->DoOrGetSomething();
  }  

Jetzt "spricht" jede Funktion nur mit Freunden, nicht mit "Freunden von Freunden".

IMHO ist es eine grobe Richtlinie, die helfen kann, Methoden zu entwickeln, die strenger dem Prinzip der Einzelverantwortung folgen. In einem einfachen Fall wie dem obigen ist es wahrscheinlich sehr fraglich, ob dies den Aufwand wirklich wert ist und ob der resultierende Code wirklich "sauberer" ist oder ob er Ihren Code nur formal ohne nennenswerten Gewinn erweitert.

Doc Brown
quelle
Dieser Ansatz hat den Vorteil, dass Unit-Tests, Debugging und Begründungen für Ihren Code erheblich vereinfacht werden.
Donnerstag,
+1. Es gibt jedoch einen sehr guten Grund , diese Codeänderung nicht vorzunehmen, da die Klassenschnittstelle mit Methoden überfüllt sein kann, deren Aufgabe darin besteht, nur einen oder mehrere Aufrufe in mehrere andere Methoden (und ohne zusätzliche Logik) zu tätigen. In einigen Arten von Programmierumgebungen, z. B. C ++ COM (insbesondere WIC und DirectX), sind im Vergleich zu anderen Sprachen mit dem Hinzufügen jeder einzelnen Methode zu einer COM-Schnittstelle hohe Kosten verbunden.
rwong
1
Im C ++ COM-Schnittstellendesign sind die Zerlegung großer Klassen in kleine Klassen (was bedeutet, dass Sie mit einer höheren Wahrscheinlichkeit mit mehreren Objekten sprechen müssen) und die Minimierung der Anzahl der Schnittstellenmethoden zwei Entwurfsziele mit echten Vorteilen (Kostenreduzierungen), die auf tiefgreifendem Verständnis beruhen der internen Mechanik (virtuelle Tabellen, Code-Wiederverwendbarkeit, viele andere Dinge). Daher müssen C ++ COM-Programmierer LoD normalerweise ignorieren.
rwong
10
+1: Das Gesetz von Demeter sollte eigentlich The Suggestion of Demeter heißen: YMMV
Binary Worrier
Das Demeter-Gesetz ist ein Ratschlag für die Auswahl der Architektur, während Sie eine kosmetische Änderung vorschlagen, sodass Sie dieses Gesetz anscheinend einhalten. Das wäre ein Missverständnis, denn eine syntaktische Änderung bedeutet nicht, dass plötzlich alles in Ordnung ist. Soweit ich weiß, bedeutete das Gesetz von Demeter im Grunde: Wenn Sie OOP machen wollen, dann hören Sie auf, überall Prodecural-Code mit Getter-Funktionen zu schreiben.
user2180613
39

Das Prinzip des geringsten Wissens oder das Gesetz von Demeter ist eine Warnung davor, Ihre Klasse mit Details anderer Klassen zu verwickeln, die Schicht für Schicht durchlaufen. Es sagt Ihnen, dass es besser ist, nur mit Ihren "Freunden" und nicht mit "Freunden von Freunden" zu sprechen.

Stellen Sie sich vor, Sie wurden gebeten, einen Schild an eine Statue eines Ritters in glänzender Plattenrüstung zu schweißen. Sie positionieren den Schild vorsichtig auf dem linken Arm, damit er natürlich aussieht. Sie bemerken, dass es drei kleine Stellen am Unterarm, am Ellbogen und am Oberarm gibt, an denen der Schild zufällig die Rüstung berührt. Sie schweißen alle drei Stellen, weil Sie sicherstellen möchten, dass die Verbindung fest ist. Stellen Sie sich vor, Ihr Chef ist verrückt, weil er den Ellbogen seiner Rüstung nicht bewegen kann. Sie nahmen an, dass sich die Rüstung niemals bewegen würde, und stellten so eine unbewegliche Verbindung zwischen Unterarm und Oberarm her. Der Schild sollte sich nur mit seinem Freund, dem Unterarm, verbinden. Nicht zu Unterarmfreunden. Auch wenn Sie ein Stück Metall hinzufügen müssen, damit sie sich berühren.

Metaphern sind nett, aber was meinen wir eigentlich mit Freund? Alles, was ein Objekt zu erstellen oder zu finden weiß, ist ein Freund. Alternativ kann ein Objekt nur verlangen, dass ihm andere Objekte übergeben werden , von denen es nur die Schnittstelle kennt. Diese zählen nicht als Freunde, da keine Erwartung auferlegt wird, wie man sie bekommt. Wenn das Objekt nicht weiß, woher es kommt, weil etwas anderes es passiert / injiziert hat, dann ist es kein Freund eines Freundes, es ist nicht einmal ein Freund. Es ist etwas, das das Objekt nur zu verwenden weiß. Das ist gut.

Wenn Sie versuchen, Prinzipien wie diese anzuwenden, ist es wichtig zu verstehen, dass sie Sie niemals daran hindern, etwas zu erreichen. Dies ist eine Warnung, dass Sie möglicherweise nicht mehr daran arbeiten, um ein besseres Design zu erzielen, das dasselbe erreicht.

Niemand möchte ohne Grund arbeiten, daher ist es wichtig zu verstehen, was Sie daraus machen. In diesem Fall bleibt Ihr Code flexibel. Sie können Änderungen vornehmen und weniger andere Klassen von den Änderungen beeinflussen lassen, um die Sie sich Sorgen machen müssen. Das hört sich gut an, hilft Ihnen aber nicht bei der Entscheidung, was Sie tun sollen, es sei denn, Sie betrachten es als eine Art religiöse Lehre.

Anstatt dieses Prinzip blind zu befolgen, nehmen Sie eine einfache Version dieses Problems. Schreiben Sie eine Lösung, die nicht dem Prinzip folgt, und eine, die es tut. Jetzt, da Sie zwei Lösungen haben, können Sie vergleichen, wie empfänglich jede für Änderungen ist, indem Sie versuchen, sie in beiden umzusetzen.

Wenn Sie ein Problem nicht lösen können, während Sie diesem Prinzip folgen, fehlt Ihnen wahrscheinlich eine weitere Fähigkeit.

Eine Lösung für Ihr spezielles Problem besteht darin, das framein etwas (eine Klasse oder Methode) einzufügen, das weiß, wie mit Frames gesprochen wird, damit Sie nicht all diese Frame-Chat-Details in Ihrer Klasse verbreiten müssen, die jetzt nur wissen, wie und wann einen Rahmen bekommen.

Das folgt eigentlich einem anderen Prinzip: Getrennte Nutzung von Konstruktion.

frame = encoder->WaitEncoderFrame()

Indem Sie diesen Code verwenden, haben Sie die Verantwortung dafür übernommen, auf irgendeine Weise eine zu erwerben Frame. Sie haben noch keine Verantwortung für das Gespräch mit a übernommen Frame.

frame->DoOrGetSomething(); 

Jetzt musst du wissen, wie man mit a spricht Frame, aber ersetze das durch:

new FrameHandler(frame)->DoOrGetSomething();

Und jetzt müssen Sie nur noch wissen, wie Sie mit Ihrem Freund FrameHandler sprechen können.

Es gibt viele Möglichkeiten, dies zu erreichen, und dies ist vielleicht nicht die beste, aber es zeigt, wie die Befolgung des Prinzips das Problem nicht unlösbar macht. Es fordert nur mehr Arbeit von dir.

Jede gute Regel hat eine Ausnahme. Die besten Beispiele, die ich kenne, sind interne domänenspezifische Sprachen . Eine DSL s Methodenkettescheint das Gesetz von Demeter ständig zu missbrauchen, weil Sie ständig Methoden aufrufen, die verschiedene Typen zurückgeben, und diese direkt verwenden. Warum ist das in Ordnung? Denn bei einem DSL ist alles, was zurückgegeben wird, ein sorgfältig entworfener Freund, mit dem Sie direkt sprechen sollen. Sie haben das Recht, von der Methodenkette eines DSL zu erwarten, dass sie sich nicht ändert. Sie haben dieses Recht nicht, wenn Sie sich nur zufällig mit der Verkettung der Codebasis befassen, was auch immer Sie finden. Die besten DSLs sind sehr dünne Darstellungen oder Schnittstellen zu anderen Objekten, auf die Sie wahrscheinlich auch nicht eingehen sollten. Ich erwähne dies nur, weil ich das Gesetz der Demeter viel besser verstanden habe, als ich erfuhr, warum DSLs ein gutes Design sind. Einige gehen sogar so weit zu behaupten, dass DSLs nicht einmal gegen das wahre Gesetz von Demeter verstoßen.

Eine andere Lösung besteht darin, etwas anderes framein dich spritzen zu lassen. Wenn Sie framevon einem Setter oder vorzugsweise einem Konstrukteur kommen, übernehmen Sie keine Verantwortung für die Konstruktion oder den Erwerb eines Rahmens. Das bedeutet, dass deine Rolle hier viel mehr so ​​ist, wie FrameHandlerssie sein würde. Stattdessen sind Sie jetzt derjenige, der mit Frameetwas anderem plaudert und herausfindet, wie man eine Frame In gewisser Weise gleiche Lösung mit einem einfachen Perspektivenwechsel erhält .

Die SOLID- Prinzipien sind die großen, denen ich zu folgen versuche. Zwei davon sind die Prinzipien der Einzelverantwortung und der Abhängigkeitsumkehr. Es ist wirklich schwer, diese beiden zu respektieren und trotzdem das Gesetz von Demeter zu verletzen.

Die Mentalität, mit der Demeter verletzt wird, ist so, als würde man in einem Buffetrestaurant essen, in dem man sich einfach schnappt, was man will. Mit ein wenig Vorarbeit können Sie sich selbst ein Menü und einen Server zur Verfügung stellen, der Ihnen alles bringt, was Sie möchten. Lehnen Sie sich zurück, entspannen Sie sich und geben Sie ein gutes Trinkgeld.

kandierte_orange
quelle
2
"Es sagt Ihnen, dass es besser ist, nur mit Ihren" Freunden "und nicht mit" Freunden von Freunden "zu sprechen" ++
RubberDuck
1
Der zweite Absatz, ist das von irgendwoher gestohlen, oder hast du es erfunden? Das hat mich dazu gebracht, das Konzept vollständig zu verstehen . Es machte deutlich, was "Freunde von Freunden" sind und welche Nachteile es hat, zu viele Klassen (Gelenke) zu verwickeln. A + Zitat.
Die Maus
2
@diemaus Wenn ich diesen Schildabsatz von irgendwoher gestohlen habe, ist seine Quelle seitdem aus meinem Kopf geleckt. Zu der Zeit dachte mein Gehirn nur, es sei klug. Woran ich mich erinnere ist, dass ich es nach vielen Upvotes hinzugefügt habe, so dass es schön ist, es validiert zu sehen. Ich bin froh, dass es geholfen hat.
candied_orange
19

Ist funktionales Design besser als objektorientiertes Design? Es hängt davon ab, ob.

Ist MVVM besser als MVC? Es hängt davon ab, ob.

Amos & Andy oder Martin und Lewis? Es hängt davon ab, ob.

Wovon hängt es ab? Die Auswahl, die Sie treffen, hängt davon ab, wie gut jede Technik oder Technologie die funktionalen und nicht funktionalen Anforderungen Ihrer Software erfüllt und gleichzeitig Ihre Design-, Leistungs- und Wartbarkeitsziele angemessen erfüllt.

[Ein Buch] sagt, dass [etwas] falsch ist.

Wenn Sie dies in einem Buch oder Blog lesen, bewerten Sie die Behauptung anhand ihres Verdienstes. das heißt, fragen Sie warum. Es gibt keine richtige oder falsche Technik in der Softwareentwicklung, es gibt nur "wie gut erfüllt diese Technik meine Ziele? Ist sie effektiv oder unwirksam? Löst sie ein Problem, sondern schafft sie ein neues? Kann sie von allen gut verstanden werden?" Entwicklungsteam, oder ist es zu dunkel? "

In diesem speziellen Fall - dem Aufrufen einer Methode für ein Objekt, das von einer anderen Methode zurückgegeben wird - ist es schwer vorstellbar, wie man die Behauptung aufstellen kann, dass es sich um eine kategorische Methode handelt, da es ein tatsächliches Entwurfsmuster gibt, das diese Praxis (Factory) kodiert falsch.

Der Grund, warum es das "Prinzip des geringsten Wissens" genannt wird, ist, dass "geringe Kopplung" eine wünschenswerte Qualität eines Systems ist. Objekte, die nicht eng miteinander verbunden sind, arbeiten unabhängiger und können daher einfacher einzeln verwaltet und geändert werden. Aber wie Ihr Beispiel zeigt, ist manchmal eine hohe Kopplung wünschenswerter, damit Objekte ihre Bemühungen effektiver koordinieren können.

Robert Harvey
quelle
2

Die Antwort von Doc Brown zeigt eine klassische Lehrbuchimplementierung von Law of Demeter - und der Verdruss, auf diese Weise Dutzende von Methoden hinzuzufügen, ist wahrscheinlich der Grund, warum sich Programmierer, einschließlich mir, oft nicht darum kümmern, selbst wenn sie es sollten.

Es gibt eine alternative Möglichkeit, die Hierarchie von Objekten zu entkoppeln:

Stellen Sie über Ihre Methoden und Eigenschaften keine interfaceTypen, sondern classTypen zur Verfügung.

Im Fall von Original Poster (OPs) encoder->WaitEncoderFrame()würde IEncoderFrameanstelle von a ein zurückgegeben Frameund definiert, welche Operationen zulässig sind.


LÖSUNG 1

Im einfachsten Fall Frameund wenn Encoderbeide Klassen von Ihnen gesteuert werden, IEncoderFramehandelt es sich um eine Teilmenge von Methoden, die Frame bereits öffentlich verfügbar macht, und es ist der EncoderKlasse egal, was Sie mit diesem Objekt tun. Die Implementierung ist dann trivial ( Code in c # ):

interface IEncoderFrame {
    void DoOrGetSomething();
}

class Frame : IEncoderFrame {
    // A method that already exists in Frame.
    public void DoOrGetSomething() { ... }
}

class Encoder {
    private Frame _frame;
    public IEncoderFrame TheFrame { get { return _frame; } }
    ...
}

LÖSUNG 2

In einem Zwischenfall, in dem die FrameDefinition nicht unter Ihrer Kontrolle steht oder die IEncoderFrameMethoden nicht hinzugefügt werden sollten , Frameist ein Adapter eine gute Lösung . Das ist die Antwort von CandiedOrange , as new FrameHandler( frame ). WICHTIG: Wenn Sie dies tun, ist es flexibler, wenn Sie es als Schnittstelle und nicht als Klasse verfügbar machen . Encodermuss wissen class FrameHandler, aber Kunden müssen nur wissen interface IFrameHandler. Oder wie ich es nannte, interface IEncoderFrame- um anzuzeigen, dass es sich speziell um ein Frame handelt, wie es vom POV des Encoders aus gesehen wird :

interface IEncoderFrame {
    void DoOrGetSomething();
}

// Adapter pattern. Appropriate if no access needed to Encoder.
class EncoderFrameWrapper : IEncoderFrame {
    Frame _frame;
    public EncoderFrameWrapper( Frame frame ) {
        _frame = frame;
    }
    public void DoOrGetSomething() {
        _frame....;
    }
}

class Encoder {
    private Frame _frame;

    // Adapter pattern. Appropriate if no access needed to Encoder.
    public IEncoderFrame TheFrame { get { return new EncoderFrameWrapper( _frame ); } }

    ...
}

COST: Zuweisung und GC eines neuen Objekts, des EncoderFrameWrapper, bei jedem encoder.TheFrameAufruf. (Sie könnten diesen Wrapper zwischenspeichern, aber das fügt mehr Code hinzu. Und es ist nur einfach, zuverlässig zu codieren, wenn das Frame-Feld des Encoders nicht durch einen neuen Frame ersetzt werden kann.)


LÖSUNG 3

In dem schwierigeren Fall, müßte die neue Wrapper über beide weiß Encoderund Frame. Dieses Objekt würde selbst gegen LoD verstoßen - es manipuliert eine Beziehung zwischen Encoder und Frame, die in der Verantwortung von Encoder liegen sollte - und es wäre wahrscheinlich ein Schmerz, das Richtige zu tun. Folgendes kann passieren, wenn Sie diesen Weg beschreiten:

interface IEncoderFrame {
    void DoOrGetSomething();
}

// *** You will end up regretting this. See next code snippet instead ***
class EncoderFrameWrapper : IEncoderFrame {
    Encoder _owner;
    Frame _frame;
    public EncoderFrameWrapper( Encoder owner, Frame frame ) {
        _owner = owner;   _frame = frame;
    }
    public void DoOrGetSomething() {
        _frame.DoOrGetSomething();
        // Hmm, maybe this wrapper class should be nested inside Encoder...
        _owner... some work inside owner; maybe should be owner-internal details ...
    }
}

class Encoder {
    private Frame _frame;

    ...
}

Das wurde hässlich. Es gibt eine weniger komplizierte Implementierung, wenn der Wrapper Details seines Erstellers / Besitzers (Encoders) berühren muss:

interface IEncoderFrame {
    void DoOrGetSomething();
}

class Encoder : IEncoderFrame {
    private Frame _frame;

    // HA! Client gets to think of this as "the frame object",
    // but its really me, intercepting it.
    public IEncoderFrame TheFrame { get { return this; } }

    // This is the method that the LoD approach suggests writing,
    // except that we are exposing it only when the instance is accessed as an IEncoderFrame,
    // to avoid extending Encoder's already large API surface.
    public void IEncoderFrame.DoOrGetSomething() {
        _frame.DoOrGetSomething();
       ... make some change within current Encoder instance ...
    }
    ...
}

Zugegeben, wenn ich wüsste, dass ich hier landen würde, würde ich das vielleicht nicht tun. Könnte nur die LoD-Methoden schreiben, und damit fertig sein. Es muss keine Schnittstelle definiert werden. Andererseits gefällt mir, dass die Schnittstelle verwandte Methoden zusammenfasst. Mir gefällt, wie es sich anfühlt, die "rahmenähnlichen Operationen" anzufertigen, die sich wie ein Rahmen anfühlen.


LETZTE KOMMENTARE

Bedenken Sie Folgendes: Wenn der Implementierer von der EncoderAnsicht war, dass das Exponieren der Frame frameGesamtarchitektur angemessen oder "so viel einfacher als das Implementieren von LoD" ist, wäre es viel sicherer gewesen, wenn er stattdessen das erste von mir gezeigte Snippet ausgeführt hätte - Exponieren einer begrenzten Teilmenge von Frame als Schnittstelle. Nach meiner Erfahrung ist das oft eine völlig praktikable Lösung. Fügen Sie der Schnittstelle nach Bedarf Methoden hinzu. (Ich spreche von einem Szenario, in dem wir wissen, dass Frame bereits über die erforderlichen Methoden verfügt, oder das Hinzufügen dieser Methoden ist einfach und unumstritten. Die "Implementierungsarbeit" für jede Methode besteht darin, der Schnittstellendefinition eine Zeile hinzuzufügen.) Und wissen, dass es auch im schlimmsten zukünftigen Szenario möglich ist, diese API funktionsfähig zu halten - hier,IEncoderFrameFrameEncoder.

Beachten Sie auch , dass , wenn Sie nicht über die Berechtigung hinzufügen müssen , IEncoderFramezu Frame, oder die benötigten Methoden passen nicht gut zu der allgemeinen FrameKlasse und Lösung # 2 nicht zu Ihnen passen, vielleicht wegen der zusätzlichen Objekterstellung-and-Zerstörung, Lösung Nr. 3 kann einfach als ein Weg gesehen werden, die Methoden zu organisieren Encoder, um das LoD zu erreichen. Gehen Sie nicht nur Dutzende von Methoden durch. Binden Sie sie in eine Schnittstelle ein und verwenden Sie "Explizite Schnittstellenimplementierung" (wenn Sie sich in c # befinden), sodass auf sie nur zugegriffen werden kann, wenn das Objekt über diese Schnittstelle angezeigt wird.

Ein weiterer Punkt, den ich hervorheben möchte, ist, dass die Entscheidung , Funktionalität als Schnittstelle verfügbar zu machen, alle drei oben beschriebenen Situationen bewältigt hat. Im ersten Fall IEncoderFramehandelt es sich einfach um eine Teilmenge der FrameFunktionalität. In der zweiten IEncoderFrameist ein Adapter. In der dritten IEncoderFrameist eine Partition in Encoders Funktionalität. Es spielt keine Rolle, ob sich Ihre Anforderungen zwischen diesen drei Situationen ändern: Die API bleibt gleich.

ToolmakerSteve
quelle
Das Koppeln Ihrer Klasse an eine Schnittstelle, die von einem ihrer Mitbearbeiter zurückgegeben wird, und nicht an eine konkrete Klasse, obwohl dies eine Verbesserung darstellt, ist immer noch eine Quelle der Kopplung. Wenn sich die Schnittstelle ändern muss, bedeutet dies, dass sich Ihre Klasse ändern muss. Der wichtige Punkt, den Sie außer Acht lassen sollten, ist, dass die Kopplung von Natur aus nicht schlecht ist , solange Sie sicherstellen, dass Sie nicht unnötig mit instabilen Objekten oder internen Strukturen koppeln . Aus diesem Grund muss das Gesetz von Demeter mit einer großen Prise Salz eingenommen werden. Es weist Sie an, immer etwas zu vermeiden, das je nach den Umständen ein Problem sein kann oder nicht.
Periata Breatta
@PeriataBreatta - dem kann und kann ich nicht widersprechen. Aber ich möchte eine Sache hinweisen: Eine Schnittstelle , per Definition, stellt dar , was muss zwischen den beiden Klassen an der Grenze bekannt. Wenn es "geändert werden muss", ist dies grundlegend - kein alternativer Ansatz hätte die erforderliche Codierung auf magische Weise vermeiden können. Vergleichen Sie dies damit, dass Sie eine der drei beschriebenen Situationen ausführen, aber keine Schnittstelle verwenden. Geben Sie stattdessen eine konkrete Klasse zurück. In 1 Frame, in 2 EncoderFrameWrapper, in 3 Encoder. Sie binden sich in diesen Ansatz ein. Die Schnittstelle kann sich an alle anpassen.
ToolmakerSteve
@PeriataBreatta ... zeigt den Vorteil der expliziten Definition als Schnittstelle. Ich hoffe, irgendwann eine IDE zu verbessern, um das so bequem zu machen, dass die Schnittstellen viel stärker genutzt werden. Die meisten Mehrebenenzugriffe würden über eine Schnittstelle erfolgen, daher ist die Verwaltung von Änderungen viel einfacher. (Wenn dies in einigen Fällen "übertrieben" ist, könnte die Codeanalyse in Kombination mit Anmerkungen darüber, wo wir bereit sind, das Risiko einzugehen, dass keine Schnittstelle vorhanden ist, im Austausch für den kleinen Leistungsschub "kompiliert" werden - und durch "ersetzt" werden eine dieser 3 konkreten Klassen aus den 3 "Lösungen".)
ToolmakerSteve
@PeriataBreatta - und wenn ich sage "die Benutzeroberfläche kann sich allen anpassen", dann sage ich nicht "ahhhh, es ist wunderbar, dass diese eine Sprachfunktion diese verschiedenen Fälle abdecken kann". Ich sage, dass das Definieren von Schnittstellen die Änderungen minimiert, die Sie möglicherweise vornehmen müssen. Im besten Fall kann sich das Design vom einfachsten Fall (Lösung 1) bis zum schwierigsten Fall (Lösung 3) ändern, ohne dass sich die Benutzeroberfläche ändert - nur die internen Anforderungen des Herstellers sind komplexer geworden. Und selbst wenn Änderungen erforderlich sind, sind sie weniger verbreitet, IMHO.
ToolmakerSteve