2009-07-27 5 views
3

Angenommen, ich habe eine Definition für eine Tür:OOD und Subjekt-Objekt Verwirrung

class Door 
{ 
    public void Lock() 
    { 
     // lock the door 
    } 
} 

Dies erschien mir sinnvoll, zumindest für eine Weile zu machen. Aber jetzt bin ich mir nicht so sicher. Wenn ich ein Person-Objekt hätte, das eine Tür sperren wollte, würde er aDoor.Lock() anrufen. Aber im wirklichen Leben verriegeln wir keine Türen, indem wir der Tür sagen, dass sie sich selbst abschließen soll.

Es scheint, als wäre ein genaueres Modell der Situation die Person, die in der Lage wäre, den Zustand von aDoor direkt zu modifizieren, vorausgesetzt, er hat genügend Kraft, um Türen zu verriegeln. Zum Beispiel sollte aCat nicht in der Lage sein, aDoor.IsLocked = true zu setzen. Ich konnte sehen, wie diese mit Eigenschaften zu tun, wenn sie Parameter unterstützt:

class Person 
{ 
    public void LockDoor(Door door) 
    { 
     door.IsLocked(this) = true; 
    } 
} 

class Door 
{ 
    bool isLocked; 

    public bool IsLocked(Person person) 
    { 
     set 
     { 
      if(person != null) // ensure there is a real person trying to lock the door 
      { 
       this.isLocked = value; 
      } 
     } 
    } 
} 

static void Main() 
{ 
    Person personFromThinAir = new Person(); 
    Door doorFromThinAir = new Door(); 
    personFromThinAir.LockDoor(doorFromThinAir); 
} 

Statt dessen, was wir tun können, ist dies:

class Person 
{ 
    public void LockDoor(Door door) 
    { 
     door.SetLocked(this, true); 
    } 
} 

class Door 
{ 
    bool isLocked; 

    public void SetLocked(Person person, bool locked) 
    { 
     if(person != null) 
     { 
      this.isLocked = locked; 
     } 
    } 
} 

Offensichtlich sind diese beiden Klassen stark gekoppelt sind und beide würden wahrscheinlich Schnittstellen, die im eigentlichen Code extrahiert wurden, aber das ist nicht das, woran ich mich stütze. Meine Frage ist, ist dies eine bessere Möglichkeit, die Beziehung zwischen den beiden Objekten zu modellieren? Gibt es einen noch besseren Weg? Je mehr ich darüber nachdenke, desto weniger Sinn für eine Tür.Lock() kann ich machen; es scheint objektorientiertes Design zu verletzen.

Antwort

9

Obwohl die Person „Sperren“ die Tür, in Wirklichkeit ist Makeln die Person (oder frobbing) an einem Element der Tür (der Schlossgriff) und diese Manipulation bewirkt, dass das Schloss die Tür verriegelt. Sie können daran denken, wo, obwohl die Person den Riegel bewegt, der Riegel die Tür verschließt - nicht die Person. Eine bessere Darstellung könnte also sein, dass eine Tür eine Sperre hat und die Person lock.lock() aufruft, wodurch die Sperre geschlossen (gesperrt) wird.

Die grundlegende Prämisse hier ist, dass, obwohl die Person die Sperre manipuliert, das ist extern (der Funktionsaufruf). Die internen Änderungen des Schlosses (der Code in der Funktion) bewirken, dass die Tür tatsächlich verriegelt wird. Die Person nimmt nicht den Griff ab und manipuliert das Innere, um die Tür jedes Mal zu verriegeln - sie schalten einfach einen Zustand auf der Außenseite um und erwarten, dass die innere Maschine damit umgeht.

+0

gut gesagt - tippte es schneller als ich! –

+0

Es hilft, tatsächlich versucht zu haben, dieses Konzept für ungefähr 4 oder 5 Jahre auch beizubringen;) Lassen Sie mich Ihnen sagen, Sie finden viele Beispiele schließlich, um zu versuchen und das Konzept von OOP durch zu bekommen – aperkins

6

Bei OOP geht es nicht darum zu modellieren, wie die Dinge in der "realen Welt" funktionieren. Es geht mehr um das Management von Komplexität. In Anbetracht dessen ist es vollkommen akzeptabel, dass sich die Tür selbst verriegelt. Selbst in der realen Welt muss eine Person, die eine Tür verriegelt, nichts über das Funktionieren des Schlosses wissen, außer das Drehen des Knopfes oder des Schlüssels.

Das Verbergen der Details einer komplexen Idee hinter einer Abstraktion macht OOP so nützlich. Die verwendeten Abstraktionen unterscheiden sich in der Problemdomäne. Im Beispiel gab man die Person sollte wissen müssen, um etwas über die Tür nicht anders als wie es zu bedienen:

class Door 
{ 
    public bool Open(){} 
    public bool Close(){} 
    public void Lock(){} 
    public void Unlock(){} 
} 
0

Das interessanteste Designproblem hier ist für mich, wie man die Kopplung zwischen dem Schließfach und dem Schließfach handhabt, da es Anforderungen gibt, die erfüllt sein müssen, damit die Verriegelung/Entriegelung erlaubt wird. Ich schaue mir diese Frage an und stelle mir ein Spiel vor, in dem ein Spieler manchmal ein Mensch sein könnte, aber manchmal eine Katze (wie im Beispiel angegeben), und vielleicht ist is_human die einzige Voraussetzung für das Sperren/Entsperren. Vielleicht möchten Sie aber auch Türen, bei denen der passende Schlüssel im Besitz des Spielers sein muss, damit das Sperren/Entsperren stattfinden kann. Wenn ja, müssen Sie das zu den Kriterien hinzufügen. Vielleicht können manche Türen nur von einer Seite und nicht von der anderen verschlossen werden, daher muss der Standort des Spielers zu den Kriterien hinzugefügt werden. Du könntest außerdem eine Fähigkeit zum Sammeln von Schlössern hinzufügen, die manche Spieler haben könnten (Katzeneinbrecher, ohne Zweifel), um ihnen die Möglichkeit zu geben, eine Tür freizuschalten (aber nicht zu verriegeln), selbst wenn sie den Schlüssel nicht hatten. Usw.

Man kann ein Gespräch zwischen den Objekten wie vorstellen:

Player: "I am trying to unlock you." 
Lock: "Do you meet requirement A?" 
Player: "Yes" 
Lock: "Do you meet requirement B?" // Only some doors would ask this. 
Player: "Yes" 
Lock: "OK, you succeed. I am unlocked!" 

Aber, werden Sie wahrscheinlich die beteiligten Felder öffentlich oder Unordnung auf der Player-Schnittstelle von Objekten gesehen belichten nicht wollen, die nicht brauchen über die Anforderungen zum Sperren/Entsperren wissen.

Ich bin kein C# -Programmierer, und es ist eine Weile her, seit ich Java gemacht habe, aber ich denke, ein Ansatz in Java, der auch in C# gelten könnte, würde das Player-Objekt eine Instanz einer lock_unlock_credentials inneren Klasse übergeben als Parameter für die /get_unlocked Methoden des Door-Objekts (oder Lock-Objekt wie vorgeschlagen). Das lock_unlock_credentials-Objekt würde Callback-Methoden haben, die aufgrund seiner inneren Klasse von Player auf relevante Felder des Players zugreifen können Objekt, aber diese Felder würden sonst nicht außerhalb des Players angezeigt. Das Lockable-Objekt könnte dann diese Callback-Methoden verwenden, um zu überprüfen, ob die Anforderungen erfüllt sind, die es interessiert. Sie können die aus den Anforderungen resultierende Kopplung nicht vermeiden, aber auf diese Weise bleiben die Details der Interaktion zwischen dem Player und dem absperrbaren Objekt erhalten.

Nicht sicher, ob derselbe innere Klassenansatz für C# gilt, aber dies als etwas zum Nachdenken präsentiert wird.