2008-12-25 4 views
5

Ich versuche ein Basisszenario mit einer Person und einem Sitz zu modellieren. Eine Person hat eine Statuseigenschaft: Sitzen oder Stehen. Ein Sitz verfügt über eine sitzende Eigenschaft, die die Person angibt, die gerade darin sitzt. Auch ist ein Sitzplatz spezielle in dem es nur bestimmte Leute "akzeptiert", um darin zu sitzen. Ich weiß, dass es seltsam klingt, wenn ein Seat jemanden "akzeptiert", aber stellen Sie sich einfach vor, dass es bestimmte Leute anderen vorzieht.Einfaches Szenario, wie man sich einbindet, fragen Sie nicht?

Nach "Tell, Don't Ask," Wie soll ich die Objekte Person und Seat so gestalten, dass sich eine Person nur dann auf einem Sitz setzen kann, wenn der Sitz ihn "akzeptiert" und auch ihren Status auf Sitzend geändert hat. Mein erster Gedanke war, dass eine Person sollte eine SitDown Methode haben wie folgt:

Person.SitDown(Seat seat); 

Aber das scheint, wie es die Klasse Person erfordern würde, um den Zustand des Sitzes zu kontrollieren, bevor in ihm sitzt, sowie mit aktualisieren der Sitz Eigenschaft Sitz (statt des Seat Aktualisieren der Eigenschaft selbst):

// inside the Person class 
void SitDown(Seat seat) { 
    if (seat.AcceptsPlayer(this)) { 
     seat.Seated = this; 
     this.Status = Sitting; 
    } 
} 

Es ist besser, scheint die Sitzklasse Griff Sitz eine Person zu haben:

Seat.SeatPerson(Person person); 

// inside Seat class 
void SeatPerson(Person person) { 
    if (IsAccepted(person)) { 
     this.Seated = person; 
     person.Status = Sitting; 
    } 
} 

Dies erfordert jedoch weiterhin, dass der Sitz den Status der Person ändert. Soll der Status der Person aktualisiert werden? Sollte nur eine Person in der Lage sein, ihren Status zu ändern? Wie würden Sie dieses einfache Szenario modellieren?

Antwort

4

Ein drittes Modell vorstellen ... Sitze, die einen Bezug sowohl zum Sitz als auch zur Person haben. Dann können Sie jedes Mal, wenn sich jemand hinsetzt, eine Instanz dieses Modells erstellen, einige Validierungen einbringen, um zwei Personen auf dem gleichen Sitz zu hindern, und vielleicht sogar einige Zeitüberschreitungen einwerfen (wenn Sie zu lange auf einem Platz sitzen, verlieren Sie ihn) .

+0

Können Sie ein Codebeispiel angeben? Ich habe Schwierigkeiten zu verstehen, wie sich der Status einer Person von Stehend zu Sitzen ändert, indem Sie das von Ihnen angegebene Seatings-Modell verwenden. – snazzer

+0

Anstelle eines Status-Flags als Membervariable verfügt die Person über eine IsSeated() -Methode, die das Seatings-Modell überprüft. Ebenso würde der Seat eine IsOccupied() -Methode haben. –

-1

lassen Sie die Person auf dem Sitz zu setzen versuchen, und aktualisieren Zustand ist abhängig vom Erfolg der Operation:

Rufen myPerson.TrySeat (targetseat), die, wenn der Sitz Prozess gelang true zurück.

//inside Person class 
     public bool TrySeat(Seat seat) 
     { 
      if (seat.TrySeat(this)) 
      { 
       Status = Sitting; 
       return true; 
      } 
      else 
      { 
       return false; 
      } 
     } 

//inside Seat class 
     internal bool TrySeat(Person person) 
     { 
      if (CanSeat(person)) 
      { 
       Seated = person; 
       return true; 
      } 
      else 
      { 
       return false; 
      } 
     } 
+2

Ich denke, genau das versucht er zu vermeiden. Sie haben auch einen Klon eingeführt, d. H. Eine Methode, die anderswo einer anderen Methode sehr ähnlich ist. –

1

Das Problem ist, dass Ihr Modell mit einer zirkulären Abhängigkeit definiert ist. Es gibt zwei Möglichkeiten, dies zu vermeiden.

Der erste folgt nicht genau "Tell, Do not Ask" explizit, aber es kommt näher auf den Punkt. Wir versuchen herauszufinden, ob wir uns setzen können, und dann dem Stuhl zu sagen, dass wir darin sitzen.

void Person.SitDown(Seat seat) { 
    if (seat.AcceptsPlayer(this)) { 
     seat.SeatPerson(this); 
     this.Status = Status.Sitting; 
    } 
} 

void Seat.SeatPerson(Person person) { 
    this.Seated = person; 
} 

Ein besserer Weg, dies zu tun (das ist der „Sag, fragen Sie nicht“ folgt expliziter) könnte die folgende sein. Wir versuchen auf dem Stuhl zu sitzen. Wenn der Stuhl uns ablehnt, wissen wir.

void Person.SitDown(Seat seat) { 
    if (seat.SeatPerson(this)) { 
     this.Status = Status.Sitting; 
    } 
    else 
    { 
     //Couldn't sit down! 
    } 
} 

bool Seat.SeatPerson(Person person) { 
    if (this.IsAccepted(person) && this.Seated == null) { 
     this.Seated = person; 
     return true; 
    } 
    else 
    { 
     return false; 
    } 
} 
+1

Das erste Beispiel sieht so aus, als hätte es eine Race Condition. AcceptsPlayer() und SeatPerson() sollten zusammen eine atomare Operation sein - vgl. Ihr zweites Beispiel mit 'IsAccepted()' private zu 'Seat', anstelle eines öffentlichen' AcceptsPlayer() '. –

1

Verwenden Sie einen Rückruf, damit jede Klasse den Status beibehalten kann, für den sie verantwortlich ist.

public class Seat 
{ 
    public void SeatPerson(Person person, Action successAction) 
    { 
    if (IsAccepted(person)) 
    { 
     this.Seated = person; 
     successAction(); 
    } 
    } 
} 


public class Person 
{ 
    public void Sit(Seat seat) 
    { 
    seat.SeatPerson(this, this.SitComplete); 
    } 

    public void SitComplete() 
    { 
    this.Status = Sitting; 
    } 
} 

Hier besteht noch eine zyklische Abhängigkeit.

Seat hat die Verantwortung zu überprüfen, ob die sitzende Person berechtigt ist, dies zu tun. Sitz trägt einen Hinweis auf die Person, sobald sie gesessen haben. Person kennt nur eine Methode, um zu versuchen, auf einem Sitzplatz zu sitzen.

Laut Vereinbarung sollte successAction nicht länger als der SeatPerson-Anruf gehalten werden. Dies garantiert, dass Seat den Zustand der Person nicht gefährden kann.

2

Riecht wie ein Sitzplatzservice. Das akzeptiert einen Sitzplatz und eine Person. Dann entscheidet, ob die Operation passieren kann.

Auf diese Weise ist die Person nur dafür verantwortlich, sich als Sitz und wo zu markieren. Der Sitz ist nur dafür verantwortlich, sich als "genommen" zu kennzeichnen.

Es ist die Verantwortung des Sitzservices zu prüfen, ob die Person & den Kriterien entspricht.

0

Sie benötigen die Seat-Klasse nicht. Die Sitzklasse verfolgt die Person, die sitzt. Stattdessen können Sie die Seat-Klasse entfernen und eine neue Methode in der Person-Klasse mit dem Namen isSitting() hinzufügen {return this.Status == Sitting; }

Verwandte Themen