2008-12-25 4 views
5

Я пытаюсь смоделировать базовый сценарий с участием Person and Seat. У человека есть свойство Status: Sitting or Standing. Сиденье имеет свойство Сидит, которое указывает Человека, который в данный момент сидит в нем. Кроме того, Seat специальный тем, что он только «принимает» определенных людей, чтобы сесть в него. Я знаю, что это звучит странно для Сита, чтобы «принять» кого-то, но просто представьте, что он предпочитает определенных людей над другими.Простой сценарий, как включить Tell Tell Не спрашивайте?

После того, как «Tell, Don't Ask» «Как создать объекты Person and Seat, чтобы человек мог сесть в сиденье, только когда сиденье« примет »его, а также изменит его статус на« Сидит ». Моя первая мысль была о том, что человек должен иметь метод SitDown следующим образом:

Person.SitDown(Seat seat); 

Но это, кажется, что это потребовало бы класс Person, чтобы проверить состояние сиденья, прежде чем сесть в него, а также необходимости обновления Сидящая собственность сИДЕНЬЯ (вместо сиденья обновление само имущество):

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

кажется, лучше иметь класс сиденья ручку сидения человека:

Seat.SeatPerson(Person person); 

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

Но это все еще требует, чтобы Сидение изменило статус человека. Это так, что статус человека должен быть обновлен? Должен ли только человек изменять свой статус? Как бы вы моделировали этот простой сценарий?

ответ

4

Ввести 3-ю модель ... Сидения, которые имеют отношение как к сиденью, так и к человеку. Затем вы можете создать экземпляр этой модели каждый раз, когда кто-то садится, забросить некоторые валидации для предотвращения двух человек, сидящих на одном и том же месте, и, возможно, даже бросить несколько тайм-аутов (если вы сидите слишком долго, вы потеряете его) ,

+0

Можете ли вы привести пример кода? Я с трудом понимаю, как меняется состояние человека с позиции «Постоянное на сидение» с использованием модели «Сидения», как вы указали. – snazzer

+0

Вместо того, чтобы иметь флаг статуса в качестве переменной-члена, у Человека должен быть метод IsSeated(), который проверяет модель размещения. Аналогично, у Seat будет метод IsOccupied(). –

-1

пусть человек пытается сесть на сиденье, и обновлять его состояние в зависимости от успеха операции:

Просто позвоните myPerson.TrySeat (targetseat), которая возвращает истину, если процесс сидит удался.

//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

Я думаю, что именно этого он и пытался избежать. Вы также вводили клон, то есть метод, который очень похож на другой метод в другом месте. –

1

Проблема заключается в том, что ваша модель определяется круговой зависимостью. Есть два способа избежать этого.

Первый из них точно не соответствует «Скажите, не спрашивайте», но он приближается к точке. Мы пытаемся выяснить, можем ли мы сесть, а затем сказать стул, что мы сидим в нем.

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

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

Лучший способ сделать это (что следует «Говори, не спрашивай» более явно) может быть следующим. Мы стараемся сидеть в кресле. Если председатель отвергает нас, мы знаем.

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

Первый пример выглядит как состояние гонки. AcceptsPlayer() и SeatPerson() должны, вместе, быть атомной операцией - ср. ваш второй пример с 'IsAccepted()' private для 'Seat', а не public' AcceptsPlayer() '. –

1

Использовать обратный вызов, чтобы каждый класс мог поддерживать состояние, за которое он несет ответственность.

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; 
    } 
} 

Здесь по-прежнему существует циклическая зависимость.

На сиденье лежит ответственность за проверку того, что человек, пытающийся сесть, действителен для этого. На сиденье есть ссылка на человека, когда они сидели. Человек знает только способ, чтобы попытаться сесть на место.

По соглашению successAction не должен удерживаться дольше, чем звонок SeatPerson. Это гарантирует, что Seat не может поставить под угрозу состояние человека.

2

Пахнет, как вам требуется сидения. Это принимает место и человека. Затем решает, может ли произойти операция.

Таким образом, человек несет ответственность за маркировку себя как сидящего и где. Сиденье несет ответственность только за маркировку себя как «взятую».

Ответственность за сидение, чтобы проверить, соответствует ли лицо & место.

0

Вам не нужен класс сиденья. Класс Seat отслеживает человека, который сидит. Вместо этого вы можете удалить класс Seat и добавить новый метод в класс Person с именем isSitting() {return this.Status == Sittting; }

 Смежные вопросы

  • Нет связанных вопросов^_^