Pregunta

Me pregunto cuál de estos sería considerado el más limpio o el mejor y por qué.

Uno de ellos expone una lista de pasajeros, lo que permite al usuario agregar y eliminar, etc. El otro oculta la lista y solo permite que el usuario los enumere y agregue utilizando un método especial.

Ejemplo 1

class Bus
{
    public IEnumerable<Person> Passengers { get { return passengers; } }
    private List<Passengers> passengers;

    public Bus()
    {
        passengers = new List<Passenger>();
    }

    public void AddPassenger(Passenger passenger)
    {
        passengers.Add(passenger);
    }
}

var bus = new Bus1();
bus.AddPassenger(new Passenger());
foreach(var passenger in bus.Passengers)
    Console.WriteLine(passenger);

Ejemplo 2

class Bus
{
    public List<Person> Passengers { get; private set; }

    public Bus()
    {
        Passengers = new List<Passenger>();
    }
}

var bus = new Bus();
bus.Passengers.Add(new Passenger());
foreach(var passenger in bus.Passengers)
    Console.WriteLine(passenger);

La primera clase que diría está mejor encapsulada. Y en este caso exacto, ese podría ser el mejor enfoque (ya que probablemente debería asegurarse de que quede espacio en el autobús, etc.). Pero supongo que podría haber casos en los que la segunda clase también podría ser útil. Como si a la clase realmente no le importa lo que le suceda a esa lista siempre que la tenga. ¿Qué te parece?

¿Fue útil?

Solución

En el ejemplo uno, es posible mutar su colección.

Considere lo siguiente:

var passengers = (List<Passenger>)bus.Passengers;

// Now I have control of the list!
passengers.Add(...);
passengers.Remove(...);

Para solucionar esto, puede considerar algo como esto:

class Bus
{
  private List<Passenger> passengers;

  // Never expose the original collection
  public IEnumerable<Passenger> Passengers
  {
     get { return passengers.Select(p => p); }  
  }

  // Or expose the original collection as read only
  public ReadOnlyCollection<Passenger> ReadOnlyPassengers
  {
     get { return passengers.AsReadOnly(); }
  }

  public void AddPassenger(Passenger passenger)
  {
     passengers.Add(passenger);
  }
 }

Otros consejos

En la mayoría de los casos, consideraría que el ejemplo 2 es aceptable siempre que el tipo subyacente sea extensible y / o exponga alguna forma de eventos onAdded / onRemoved para que su clase interna pueda responder a cualquier cambio en la colección.

En este caso, List < T > no es adecuado ya que no hay forma de que la clase sepa si se ha agregado algo. En su lugar, debe usar una Colección porque la Colección & Lt; T & Gt; La clase tiene varios miembros virtuales (Insertar, Eliminar, Establecer, Borrar) que se pueden anular y agregar activadores de eventos para notificar a la clase de ajuste.

(También debe tener en cuenta que los usuarios de la clase pueden modificar los elementos de la lista / colección sin que la clase primaria lo sepa, así que asegúrese de no confiar en que los elementos no se modifiquen, a menos que obviamente son inmutables, o puede proporcionar eventos de estilo onChanged si lo necesita).

Ejecute sus ejemplos respectivos a través de FxCop y eso debería darle una pista sobre los riesgos de exponer List<T>

Diría que todo se reduce a tu situación. Normalmente elegiría la opción 2, ya que es la más simple, a menos que tenga una razón comercial para agregarle controles más estrictos.

La opción 2 es la más simple, pero permite que otras clases agreguen / eliminen elementos a la colección, lo que puede ser peligroso.

Creo que una buena heurística es considerar lo que hacen los métodos de envoltura. Si su método AddPassenger (o Remove, u otros) simplemente retransmite la llamada a la colección, entonces elegiría la versión más simple. Si tiene que verificar los elementos antes para insertarlos, entonces la opción 1 es básicamente inevitable. Si tiene que hacer un seguimiento de los elementos insertados / eliminados, puede ir en cualquier dirección. Con la opción 2, debe registrar eventos en la colección para recibir notificaciones, y con la opción 1, debe crear contenedores para cada operación en la lista que desee usar (por ejemplo, si desea Insertar y Agregar), así que supongo depende.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top