简单的场景,如何合并告诉不要问?

时间:2008-12-25 09:20:31

标签: c# tell-dont-ask

我正在尝试模拟涉及人员和座位的基本情景。人具有身份属性:坐着或站立。一个席位有一个Seated属性,用于指定当前位于其中的Person。此外,座位特殊,因为它只“接受”某些人坐在其中。我知道座位“接受”某人听起来很奇怪,但只是想象它更喜欢某些人而不是其他人。

在“Tell, Don't Ask之后,”我应该如何设计人物和座位对象,以便只有当座位“接受”他并且他的状态改为“坐着”时,人才可以坐在座位上。我的第一个想法是一个Person应该有一个SitDown方法如下:

Person.SitDown(Seat seat);

但这似乎需要Person类在坐之前检查Seat的状态,以及必须更新Seat的Seated属性(而不是更新属性本身的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 个答案:

答案 0 :(得分:4)

介绍第3个模型......座位既包含座位,也包含人物。然后你可以在每次有人坐下时创建该模型的实例,投入一些验证以防止两个人坐在同一个座位上,甚至可能会抛出一些超时(如果你坐在座位上太长时间,你会失去它)

答案 1 :(得分:2)

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

这样,这个人只负责将自己标记为坐着和在哪里。 该座位仅负责将自己标记为“已拍摄”。

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

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

答案 3 :(得分: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不会危及Person的状态。

答案 4 :(得分:0)

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

答案 5 :(得分:-1)

让这个人试着坐在座位上,并根据操作的成功更新它的状态:

只需调用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;
            }
        }