Ist die Ableitung Quadrat von Rechteck eine Verletzung des Liskov ' s substitutionsprinzip?
Ich bin neu in design und lernen die Grundsätze der Gestaltung.
Er sagt, die Ableitung Quadrat von Rechteck ist ein klassisches Beispiel für die Verletzung des Liskov ' s substitutionsprinzip.
Wenn das der Fall ist, was sollte die richtige design?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich glaube, die Argumentation ist so etwas wie dieses:
Lassen Sie uns sagen, Sie haben eine Methode, die annimmt, ein Rechteck und passt seine Breite:
Sollte es durchaus sinnvoll, angesichts dessen, was ein Rechteck ist, davon ausgehen, dass dieser test weitergeben würde:
... da ändern die Breite eines Rechtecks hat keinen Einfluss auf seine Höhe.
Allerdings, sagen wir mal, Sie haben abgeleitet, die eine neue Square-Klasse Rechteck. Per definition, ein Quadrat hat die Höhe und Breite immer gleich. Wir versuchen, dass Sie den test erneut:
Test wird fehlschlagen, da ein Quadrat Breite 100, ändert sich auch seine Höhe.
So, Liskov ' s substitutionsprinzip verletzt wird durch Ableitung Quadrat von Rechteck.
Den "ist-ein" - Regel macht es Sinn, in der "realen Welt" (ein Platz ist definitiv eine Art Rechteck), aber nicht immer in der Welt der software-Gestaltung.
Bearbeiten
Ihre Frage zu beantworten, die richtige design sollte wohl sein, dass sowohl Rechteck und Quadrat der Ableitung von einer gemeinsamen "Polygon" oder "Form" - Klasse, die erzwingt keine Regeln in Bezug auf Breite oder Höhe.
Hängt die Antwort von der Veränderbarkeit. Wenn dein Rechteck und Quadrat-Klassen sind immutable, dann
Square
ist wirklich ein Untertyp vonRectangle
und es ist völlig OK, die Ableitung der ersten aus der zweiten. AnsonstenRectangle
undSquare
konnte beide setzen eineIRectangle
ohne Mutatoren, aber die Ableitung, aus der anderen ist falsch, da weder Typ ist richtig ein Untertyp des anderen.IShape
mehr Sinn macht, als dieIRectangle
in diesem Zusammenhang. Was denkst du?IShape
würde Sinn machen, in einem Kontext betrachtet, in allen Formen, einschließlich nicht-rechteckig sind, aber das context-wir diskutieren hier nicht. Wir reden hier nur Quadrate und Rechtecke hier, Dreiecke und Kreise brauchen sich nicht zu bewerben.Ich nicht damit einverstanden, dass die Ableitung Quadrat von Rechteck unbedingt gegen LSP.
In Matt ' s Beispiel, wenn Sie code haben, der setzt auf Breite und Höhe unabhängig sein, dann hat es in der Tat verletzen LSP.
Wenn jedoch, können Sie ersetzen Sie es mit einem Rechteck ein Quadrat überall in Ihrem code, ohne zu brechen keine Annahmen, dann sind Sie nicht verletzen LSP.
Also es kommt wirklich darauf an, was die Abstraktion Rechteck bedeutet in Ihre Lösung.
Ich habe gekämpft, mit diesem problem in letzter Zeit viel und dachte, ich würde meinen Hut in den ring:
Ankündigung der letzten Klasse
ResizableRectangle
. Durch verschieben der "resizableness" in einer Unterklasse, die wir bekommen, code wieder zu verwenden, während tatsächlich die Verbesserung unser Modell. Betrachten Sie es wie folgt: ein Quadrat kann nicht frei geändert werden, während verbleibenden ein Quadrat, in der Erwägung, dass nicht-quadratische Rechtecke können. Nicht alle Rechtecke können in der Größe verändert werden, aber, da ein Platz ist ein Rechteck (und es kann nicht frei geändert werden, während dabei seine "Identität"). (o_O) es macht Also Sinn, um eine Basis zu machenRectangle
Klasse, die nicht in der Größe angepasst, da dies eine zusätzliche Eigenschaft von einige Rechtecke.Square
aus, die nicht der Platz durch eine unterschiedliche Breite und Höhe.Nehmen wir an, die Klasse Rechteck mit den beiden (der Einfachheit halber public) Eigenschaften Breite,Höhe. Wir können diese beiden Eigenschaften: r.Breite=1, r.Höhe=2.
Jetzt sagen wir ein Quadrat is_a Rechteck. Aber wenn der Anspruch ist, "ein Quadrat verhält sich wie ein Rechteck" können wir nicht einstellen .Breite=1 und .Höhe=2 auf eine quadratische Objekt (Ihrer Klasse wahrscheinlich passt die Breite, wenn Sie die Höhe und Umgekehrt). So gibt es mindestens einen Fall, wo ein Objekt vom Typ Quadrat verhält sich nicht wie ein Rechteck und daher kann man nicht ersetzen (komplett).
Ich glaube, dass OOD/OOP-Techniken bestehen, um die software zur Darstellung der realen Welt. In der realen Welt ein Quadrat ist ein Rechteck, das hat gleich lange Seiten. Das Quadrat ist ein Quadrat, nur weil es gleich lange Seiten hat, nicht, weil es beschloss, ein Quadrat. Also das OO-Programm muss sich mit ihm beschäftigen. Natürlich, wenn die routine das Objekt instanziiert will es quadratisch sein, es könnte geben Sie die length-Eigenschaft und width-Eigenschaft als gleich den gleichen Betrag. Wenn Sie das Programm über das Objekt wissen muss, um später, wenn Sie quadratisch ist, muss es nur Fragen. Das Objekt konnte eine nur-lese-Boolesche Eigenschaft namens "Quadrat". Wenn die aufrufende routine ruft es, das Objekt zurückgeben kann (Länge = Breite). Nun dies kann auch dann der Fall, wenn das Rechteck-Objekt ist unveränderlich. Darüber hinaus, wenn das Rechteck ist in der Tat unveränderlich sind, wird der Wert der Quadratischen Eigenschaft kann festgelegt werden, in der Konstruktor-und mit ihm getan werden. Warum ist das ein Problem? Die LSP erfordert sub-Objekte unveränderlich anwenden und square ein sub-Objekt ein Rechteck wird Häufig als ein Beispiel für seine Verletzung. Aber das scheint nicht zu sein, gutes design, weil wenn die mit routine ruft das Objekt als "objSquare", muss wissen, dass seine inneren detail. Wäre es nicht besser, wenn es nicht egal, ob das Rechteck ein Quadrat war oder nicht? Und das wäre, da das Rechteck die Methoden richtig wäre unabhängig. Gibt es ein besseres Beispiel, wenn das LSP verletzt wird?
Noch eine Frage: wie wird ein Objekt unveränderlich sind? Gibt es eine "Unveränderliche" Eigenschaft, die bei der Instanziierung?
Fand ich die Antwort und es ist das, was ich erwartet hatte. Da ich ein VB .NET-Entwickler, das ist das, was mich interessiert. Aber die Konzepte sind die gleichen in allen Sprachen. In VB .NET, die Sie erstellen, immutable Klassen, indem Sie die Eigenschaften nur-Lesen und verwenden Sie den Neuen Konstruktor zu erlauben die Instanziierung routine angeben Eigenschaft Werten, wenn das Objekt erstellt wird. Sie können auch Konstanten verwenden, die für einige der Eigenschaften, und Sie werden immer dasselbe sein. Von der Erstellung forward das Objekt ist unveränderlich.
Das problem ist, dass das, was da beschrieben wird ist nicht wirklich ein "Typ", sondern einer kumulativen Eigenschaft.
Alles, was Sie wirklich haben ist ein viereck, und dass beide "Rechtwinkligkeit" und "rectangleness" sind nur emergenten Artefakte, abgeleitet von den Eigenschaften der Winkel und Seiten.
Das gesamte Konzept von "Platz" (oder auch Rechteck) ist nur eine abstrakte Repräsentation einer Sammlung von Eigenschaften des Objekts in Bezug zu einander und das Objekt in Frage, nicht die Art von Objekt es sich selbst.
Dies ist, wo denken, das problem in den Kontext einer typeless Sprache kann Ihnen dabei helfen, denn es ist nicht der Typ, der bestimmt, ob es ein "square", aber die tatsächlichen Eigenschaften des Objekts, das bestimmt, ob es ein "square".
Ich denke, wenn Sie wollen, um die Abstraktion noch weiter, würden Sie nicht auch sagen, Sie haben ein viereck aber, dass Sie ein polygon oder auch nur eine Form.
Seine ziemlich einfach 🙂 Die 'Basis' der Klasse (die erste in der Ableitung Kette) sollten die meisten Allgemeinen.
Z.B. Form -> Rechteck -> Quadrat.
Hier ein Quadrat ist ein Spezialfall eines Rechtecks (mit der eingeschränkten Maße) und ein Rechteck ist ein Spezialfall einer Form.
Sagte eine andere Art und Weise - Verwendung der "ist" - test. Ein knappe ist ein Rechteck. Aber ein rectange ist nicht immer ein Quadrat.