Простой сценарий, как включить, скажи, не спрашивай? - PullRequest
5 голосов
/ 25 декабря 2008

Я пытаюсь смоделировать базовый сценарий, включающий человека и место. Человек имеет свойство Status: сидя или стоя. Место имеет свойство Seated, в котором указывается лицо, которое в данный момент находится в нем. Кроме того, место является особенным в том смысле, что оно «принимает» только определенных людей. Я знаю, что для Seat звучит странно «принимать» кого-то, но просто представьте, что он предпочитает некоторых людей другим.

После " Скажите, не спрашивайте ", как мне сконструировать объекты "Человек" и "Сиденье", чтобы Человек мог сесть в Сиденье только тогда, когда Сиденье "принимает" его, а также иметь его статус изменился на Сидя. Моей первой мыслью было, что у человека должен быть метод SitDown следующим образом:

Person.SitDown(Seat seat);

Но, похоже, для этого необходимо, чтобы класс Person проверял состояние Seat перед тем, как сидеть в нем, а также обновлял свойство Seat Seat (вместо того, чтобы Seat обновлял само свойство):

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

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

Seat.SeatPerson(Person person);

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

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

Ответы [ 6 ]

4 голосов
/ 25 декабря 2008

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

2 голосов
/ 15 января 2013

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

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

Служба рассадки несет ответственность за проверку соответствия лица и места критериям.

1 голос
/ 25 декабря 2008

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

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 не может поставить под угрозу состояние человека.

1 голос
/ 25 декабря 2008

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

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

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;
    }
}
0 голосов
/ 14 мая 2015

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

0 голосов
/ 25 декабря 2008

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

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

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