patterns pattern gof example book c# .net oop design-patterns class-design

c# - pattern - ¿Es este mal diseño oop?



factory pattern design c# (7)

¿Por qué no le das a tu clase de pollo un método "Actualizar (algunos parámetros ...)"? A continuación, puede simplemente instanciar un pollo por

Chicken chicken = new Chicken("Name", "descr");

y actualización por:

chicken.Update(myparameters..);

EDITAR

public class Chicken { public Chicken(string name, string description) { this.Name = name; this.Description = description; } public string Name { get; set; } public string Description { get; set; } // Fill in all the other properties! public int EggsDroppedInLife { get; set; } }

Y ahora puedes usar tu clase de pollo de la siguiente manera:

Chicken chicken = new Chicken("Harry", "Nice chick"); chicken.NumberOfEggs = 123; chicken.Description = "Oh no, it''s actually not nice."; // ... change all the properties as you want

Tengo una clase llamada Chicken y en Chicken tengo algunos métodos, así que en otra clase en la que hago una instancia y llamo a métodos sobre Chicken, podría hacer algo como esto:

Chicken chicken = new Chicken("Name","Description") public void UpdateChicken(Chicken chicken) { chicken.Update(chicken); }

¿Lo anterior está bien o presenta problemas? Si es así, es mejor tener otra clase, como ChickenCalculations y hacer algo como:

public void UpdateChick(Chicken chicken) { ChickenCalculations.Update(chicken); }

Aquí hay una implementación:

Chicken chicken = new Chicken("Bob","Coolest Chicken", 4, 123, 5, 388, true, false, true); Chicken anotherChicken = new Chicken() anotherChicken.Update(chicken); chicken.Update(chicken)

Aquí hay un ejemplo más práctico en lugar de usar un pollo:

public class AirlineBooking { int BookingId {get;set;} string Name {get;set;} string Description {get;set;} decimal Price {get;set;} decimal Tax {get;set;} string seat {get;set;} bool IsActive {get;set;} bool IsCanceld {get;set;} public AirlineBooking(string name, string description, decimal price, decimal tax, string seat, bool isActive, bool isCanceled) { Name = name; Description = description; Price = price; Tax = tax; Seat = seat; IsActive = isActive; IsCanceled = isCanceled; } public Update(AirlineBooking airlineBooking, int id) { //Call stored proc here to update booking by id } public class BookingSystem { //Create new booking AirlineBooking booking = new AirlineBooking("ticket-1", "desc",150.2,22.0, "22A",true, false); //Change properties and update. booking.Name ="ticket-2"; booking.Description = "desc2"; booking.Price = 200.52; booking.Tax = 38.50; public void UpdateBooking(AirlineBooking booking, int id) { /* This is the meat of the question, should the passed in booking to update itself or should I have a Service Class , such as AirlineBookingOperations with an update method. */ booking.Update(booking,id); } } }


La idea general de la Programación Orientada a Objetos es pensar que los objetos pueden actuar sobre sí mismos.

Así que solo debes usar chicken.Update() para actualizar un pollo.


Los objetos deben encapsular la funcionalidad. La funcionalidad debe pasarse para dar flexibilidad al objeto encapsulado.

Por lo tanto, si está guardando la gallina, debe pasar la funcionalidad del repositorio. Si tiene cálculos de pollo, y son propensos a cambiar, también se debe pasar.

class Chicken { IChickenCalculations ChickenCalculations; IChickenRepository ChickenRepository; Chicken(IChickenCalculations chickenCalculations, IChickenRepository chickenRepository) { ChickenCalculations = chickenCalculations; ChickenRepository = chickenRepository ; } Calculate() { ChickenCalculations.Calculate(this); } Update() { ChickenRepository.Update(this); } }

Tenga en cuenta que en este ejemplo, el pollo es capaz de realizar cálculos en sí mismo y persistir, sin tener ningún conocimiento de cómo realizar cálculos o cosas persistentes (después de todo, es solo un pollo).


Para entornos de multiproceso, es mejor tener una clase separada como ChickenCalculations. Cuando necesite realizar algunos otros pasos además de lo que hace chicken.Update (), puede hacerlo con la clase ChickenCalculations. Por lo tanto, si varias clases que crean instancias y métodos de Chicken no tienen que preocuparse por las mismas cosas que la clase ChickenCalculations está cuidando.


Si bien me doy cuenta de que no hay Chicken , podría haber un método de Update en tu objeto real, ¿verdad?

Creo que deberías intentar introducir algo más que "actualizar" en términos de lenguaje. No hay manera de entender realmente lo que hace la actualización. ¿Se acaba de actualizar los "datos" en el pollo? En ese caso, ¿qué datos? Y también, ¿se le debería permitir actualizar una instancia de Chicken así?

Prefiero ver cosas como

chicken.CanFly = false; if(chicken.CanFly) // inherited from Bird :) ckicken.FlyTo(point); else chicken.WalkTo(point);

Aquí hay un ejercicio bastante interesante en OOP: http://milano-xpug.pbworks.com/f/10080616-extreme-oop.pdf


Voy a usar su clase de AirlineBooking como ejemplo porque muchas personas parecen haberse confundido con el ejemplo de Chicken .

Algunos introducción:

El principio de responsabilidad única establece que un objeto debe tener una responsabilidad única y que solo debe ocuparse de las cosas que están alineadas con esa responsabilidad. Por ejemplo, un TaxCalculator solo debe ser responsable de calcular los impuestos y no, por ejemplo, con la conversión de moneda: este es el trabajo del CurrencyConverter .

A menudo, esta es una idea realmente buena , ya que significa que su aplicación está estructurada en trozos de código, cada uno con una sola responsabilidad hace que sea más fácil de entender y más seguro de cambiar. Otra forma de poner esto es que una clase o módulo debe tener una y solo una razón para cambiar, por ejemplo, "La forma en que calculamos el impuesto ha cambiado" o "La forma en que convertimos la moneda ha cambiado".

Las preguntas que debes hacerte son:

  • ¿Cuál es la responsabilidad de AirlineBooking ?
  • ¿Actualizar una aerolínea es parte de esa responsabilidad?

Por ejemplo, en este caso, diría que la responsabilidad de AirlineBooking es "encapsular una reserva de una aerolínea", y que actualizar una reserva de aerolínea es de hecho responsabilidad del sistema de reserva, no de AirlineBooking .

Alternativamente, otra forma de pensar acerca de esto es que si pongo el método de Update en AirlineBooking esto significaría que:

  • Si el sistema de reservas cambia para usar un servicio web en lugar de un procedimiento almacenado, entonces la clase AirlineBooking debe cambiar.
  • Si la encapsulación de una reserva de una aerolínea cambia (tal vez es posible suspender una reservación, o el nombre de la aerolínea ahora está registrado) entonces AirlineBooking debe cambiar.

Es decir, AirlineBooking ahora tiene muchas razones diferentes para cambiar, por lo que no debería ser responsable de "Actualizar"

En resumen, probablemente haría esto:

public class AirlineBooking { public int BookingId {get;set;} /* Other properties */ } public class BookingSystem { public void UpdateBooking(AirlineBooking booking, int id) { // Call your SP here. } }

La razón por la que debe AirlineBooking estas preguntas es porque depende de para qué se utilice AirlineBooking en su aplicación.

Por ejemplo, si AirlineBooking está "al tanto" (es decir, tiene una referencia a) el sistema de reservas, entonces podría agregar un método "auxiliar", como este:

public class AirlineBooking { public void Update(int id) { this.bookingSystem.UpdateBooking(this, id); } }


¿Por qué la función UpdateChicken no es un miembro de la clase Chicken ?

De esa forma, no tendría que pasar una instancia de un objeto Chicken , sino que simplemente debería llamar al método Update en una instancia existente:

Chicken chicken = new Chicken("Name", "Description"); chicken.Update();

En general, es mejor encapsular todos los métodos que operan en una clase particular dentro de esa clase, en lugar de dividirlos en una clase "auxiliar" separada. ¡Dejemos que los pollos se las apañen!