5

I'm trying to model a basic scenario involving a Person and a Seat. A Person has a Status property: Sitting or Standing. A seat has a Seated property that specifies the Person that is currently sitting in it. Also, a Seat is special in that it only "accepts" certain people to sit in it. I know it sounds strange for a Seat to "accept" someone, but just imagine it prefers certain people over others.

Following "Tell, Don't Ask," How should I design the Person and Seat objects so that a Person can sit down in a Seat only when the Seat "accepts" him and also have his status changed to Sitting. My first thought was that a Person should have a SitDown method as follows:

Person.SitDown(Seat seat);

But this seems like it would require the Person class to inspect the state of the Seat before sitting in it, as well as having to update the Seat's Seated property (instead of the Seat updating the property itself):

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

It seems better to have the Seat class handle seating a person:

Seat.SeatPerson(Person person);

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

But this still requires the Seat to change the person's status. Is this the way that the person's status should be updated? Should only a Person be able to change his status? How would you model this simple scenario?

4

6 回答 6

4

Introduce a 3rd model... Seatings that has a reference to both the seat, and the person. Then you can create an instance of that model every time someone sits down, throw in some validations for preventing two people sitting in the same seat, and maybe even throw in some timeouts (if your sitting in a seat too long, you lose it).

于 2008-12-25T09:30:06.767 回答
2

闻起来像你需要座位服务。那接受一个座位和一个人。然后决定是否可以进行操作。

这样,该人只需负责将自己标记为就座和位置。座位只负责将自己标记为“已占用”。

检查人员和座位是否符合标准是座位服务的责任。

于 2013-01-15T18:35:35.617 回答
1

The problem is your model is defined with a circular dependency. There are two ways of avoiding this.

The first one doesn't exactly follow "Tell, Don't Ask" explicitly, but it gets closer to the point. We try to find out if we can sit down, then tell the chair that we're sitting in it.

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

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

A better way to do this (which follows the "Tell, Don't Ask" more explicitly) might be the following. We try to sit in the chair. If the chair rejects us, we know.

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;
    }
}
于 2008-12-25T09:35:44.180 回答
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;
  }
}

这里仍然存在周期性依赖。

Seat 有责任检查试图就座的人是否有效。一旦他们坐下,Seat 就会引用该人。人们只知道尝试坐在座位上的方法。

按照惯例,successAction 的持续时间不应超过 SeatPerson 调用。这保证了 Seat 不会损害 Person 的状态。

于 2008-12-25T13:53:18.233 回答
0

您不需要 Seat 类。Seat 类跟踪坐着的人。相反,您可以删除 Seat 类并在名为 isSitting() 的 Person 类中添加一个新方法 { return this.Status == Sitting; }

于 2015-05-14T09:59:16.053 回答
-1

let the person try to seat on the seat, and update it's state depending on the success of the operation:

Just call myPerson.TrySeat(targetseat), which returns true if the sitting process succeeded.

//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;
            }
        }
于 2008-12-25T09:34:51.420 回答