2008-12-25 17 views
5

Estoy tratando de modelar un escenario básico que involucre una Persona y un Asiento. Una persona tiene una propiedad de estado: sentado o de pie. Un asiento tiene una propiedad Sentada que especifica la Persona que se encuentra actualmente en él. Además, un asiento es especial en el sentido de que solo "acepta" a ciertas personas para sentarse en él. Sé que suena extraño que un Asiento "acepte" a alguien, pero imagínese que prefiere a ciertas personas sobre otras.Escenario simple, cómo incorporarlo Tell Do not Ask?

Siguiendo "Tell, Don't Ask," ¿Cómo debo diseñar los objetos Persona y Asiento para que una Persona pueda sentarse en un Asiento solo cuando el Asiento "lo acepte" y también que su estado cambie a Sentado? Mi primer pensamiento fue que una persona debe tener un método de brazos caídos de la siguiente manera:

Person.SitDown(Seat seat); 

Pero esto parece que requeriría la clase Person para inspeccionar el estado del asiento antes de sentarse en ella, así como tener que actualizar propiedad asentada del asiento (en lugar del asiento de la actualización de la propiedad en sí):

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

parece mejor tener la manija de la clase de asiento del asiento a una persona:

Seat.SeatPerson(Person person); 

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

Pero esto todavía requiere que Seat cambie el estado de la persona. ¿Es esta la manera en que se debe actualizar el estado de la persona? ¿Debería solo una Persona poder cambiar su estado? ¿Cómo modelarías este simple escenario?

Respuesta

4

Presente un tercer modelo ... Asientos que hacen referencia tanto al asiento como a la persona. Luego puede crear una instancia de ese modelo cada vez que alguien se siente, arrojar algunas validaciones para evitar que dos personas se sienten en el mismo asiento, y tal vez incluso emitir algunos tiempos de espera (si se sienta en un asiento demasiado tiempo, lo pierde) .

+0

¿Puede proporcionar un ejemplo de código? Tengo dificultades para entender cómo cambia el estado de una persona de estar de pie a sentado usando el modelo de los asientos como usted ha especificado. – snazzer

+0

En lugar de tener una bandera de Estado como variable miembro, la Persona tendría un método IsSeated() que verifica el modelo de Seatings. Del mismo modo, el asiento tendría un método IsOccupied(). –

-1

dejar que la persona trate de sentarse en el asiento, y actualizar su estado en función del éxito de la operación:

Sólo tiene que llamar myPerson.TrySeat (targetseat), que devuelve verdadero si el proceso de estar sucedió.

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

Creo que eso es precisamente lo que está tratando de evitar. También introdujo un clon, es decir, un método que es muy similar a otro método en otro lugar. –

1

El problema es que su modelo se define con una dependencia circular. Hay dos formas de evitar esto.

La primera no sigue exactamente "Tell, Do not Ask" explícitamente, pero se acerca más al punto. Intentamos averiguar si podemos sentarnos, luego decirle a la silla que estamos sentados en ella.

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

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

Una mejor manera de hacer esto (que sigue el "Tell, no piden" más explícitamente) podría ser el siguiente. Tratamos de sentarnos en la silla. Si la silla nos rechaza, lo sabemos.

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

El primer ejemplo parece que tiene una condición de carrera. AcceptsPlayer() y SeatPerson() deberían, juntos, ser una operación atómica - cf. su segundo ejemplo con 'IsAccepted()' private a 'Seat', en lugar de' AcceptsPlayer() 'público. –

1

Utilice una devolución de llamada para que cada clase pueda mantener el estado del cual es responsable.

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

Aquí todavía hay dependencia cíclica.

Seat tiene la responsabilidad de verificar que la persona que intenta sentarse sea válida para hacerlo. El asiento lleva una referencia a la persona una vez que se han sentado. La persona solo conoce un método para tratar de sentarse en un asiento.

Por convención, successAction no debe mantenerse durante más tiempo que la llamada de SeatPerson. Esto garantiza que Seat no puede comprometer el estado de la persona.

2

Huele como si necesitara un servicio de asientos. Eso acepta un asiento y una persona. Luego decide si la operación puede suceder.

De esta manera, la persona es la única responsable de marcarse a sí misma como sentada y en el lugar. El asiento es el único responsable de marcarse como "tomado".

Es responsabilidad del servicio de asientos comprobar si la persona & asiento cumplía los criterios.

0

No necesita la clase Seat. La clase Seat realiza un seguimiento de la persona que está sentada. En su lugar, puede eliminar la clase Seat y agregar un nuevo método en la clase Person llamada isSitting() {return this.Status == Sittting; }

Cuestiones relacionadas