2012-04-26 10 views
5

Ok, he buscado y no he podido encontrar una solución adecuada para mi problema, estoy rediseñando una parte de nuestro sistema de punto de venta. Vamos a suponer que tenemos las siguientes clases:Cómo diseñar la dependencia de clase tratando de evitar la Ley de Demeter

TWorkShift = class 
    Date: TDateTime; 
    fTotalSold: Currency; 
    fSales: TList<TSale>; 
public 
    property TotalSold: Currency read fTotalSold write fTotalSold; 
    property Sales: Currency read fSales write fSales; 
end; 

TSale = class 
    fAmount: Currency; 
    fWorkShift: TWorkShift; 
public 
    property Amount: Currency read fAmount write fAmount; 
    procedure Save; 
end; 

Ahora, el problema que estoy enfrentando está tratando de llegar a la mejor idea sin violar la Ley de Demeter. Lo que estoy tratando de lograr es la siguiente:

  1. Cada vez que un nuevo Tsalé se guarda Quiero añadir a la lista de ventas de la TWorkShift del usuario actual, y también quiero sumar la cantidad de la venta a "TotalSold" de TWorkShift.

he intentado dos enfoques diferentes:

Enfoque A:

// Vamos a suponer que tenemos un turno de trabajo con el ID de 1 y se carga de base de datos con: CurrentShift: = TWorkShift.Create (1);

NewSale := TSale.Create; 
NewSale.Amount:=100; 
NewSale.Save; 

CurrentShift.Sales.Add(NewSale); 
CurrentShift.TotalSold := CurrentShift.TotalSold + NewSale.Amount; 

El problema con este enfoque es que está difícil de probar, porque quiero encapsular la lógica de la suma en algunas de las clases o en algún otro lugar (una nueva clase tal vez?).

Enfoque B:

Mi otro enfoque está incluido el código dentro de la clase en sí Tsalé:

procedure TSale.Save; 
begin 
    SaveToDataBase; 

    fWorkShift.Sales.Add(Self); 
    fWorkShift.TotalSold := fWorkShift.TotalSold + Self.Amount; 
end; 

Este enfoque Creo que viola la Ley de Demeter e Indiferente siente bien para mí .

Quiero encontrar una "forma correcta" de hacerlo maximizando la simplicidad del código y facilitando el mantenimiento en el futuro. Entonces, cualquier sugerencia sería apreciada.

Gracias

Respuesta

3

Si desea agregar una venta a TWorkShift, entonces usted debe tener

TWorkShift.AddSale(aSale: TSale); 
begin 
    Sales.Add(aSale); 
end; 

En otras palabras, TWorkShift debe "pedir" lo que necesita.

Además, no veo ningún motivo para que TSale tenga un campo TWorkShift. Un turno laboral tiene muchas ventas, pero ¿por qué una venta tiene un WorkShift?

+0

Gracias Nick, Bueno, en este caso estoy usando el marco Aurelio ORM, así que tengo una "asociación" con el fin de obtener información tal como: 'Venta: = Manager.Find (1); ShowMessage ('La venta se vendió en el turno de trabajo con ID:' + IntToStr (Sale.Shift.ID)); ' Esto es necesario porque a veces necesito mostrar toda la información sobre una venta, como el turno en el que se vendió, la fecha, el cajero, etc. –

+1

Luis, eso es un problema para la capa de presentación no el BL. La capa de presentación debe reunir toda la información necesaria. Entonces, en su caso podría recuperar el objeto de venta del objeto de turno de trabajo y tener toda la información. – whosrdaddy

+0

Luis: si un ORM le obliga a hacerlo, entonces probablemente deba considerar el uso de un ORM diferente. Eso es un mal diseño: una Venta no debería saber nada sobre el Workshift en el que sucedió. ¿Qué sucede si quiere vender cosas de cualquier Workshift? –

0

Está haciendo algo cuando agrega elementos a un TList para que pueda usar el OnNotify. No sé si Aurelius también está usando ese evento, así que agregué un código para eso. Solo tiene que ver si la asignación de OnNotify puede suceder dentro del marco después de que la lista se haya asignado a su objeto TWORKSHIFT porque entonces podría sobrescribir el controlador de eventos NotifySales.

type 
    TWorkShift = class 
    private 
    Date: TDateTime; 
    fTotalSold: Currency; 
    fSales: TList<TSale>; 
    fNotifySales: TCollectionNotifyEvent<TSale>; 
    procedure NotifySales(Sender: TObject; const Item: TSale; 
     Action: TCollectionNotification); 
    procedure SetSales(const Value: TList<TSale>); 
    public 
    property TotalSold: Currency read fTotalSold write fTotalSold; 
    property Sales: TList<TSale> read fSales write SetSales; 
    end; 

procedure TWorkShift.NotifySales(Sender: TObject; const Item: TSale; 
    Action: TCollectionNotification); 
begin 
    if Assigned(fNotifySales) then 
    fNotifySales(Sender, Item, Action); 

    case Action of 
    cnAdded: fTotalSold := fTotalSold + Item.Amount; 
    cnRemoved: fTotalSold := fTotalSold - Item.Amount; 
    end; 
end; 

procedure TWorkShift.SetSales(const Value: TList<TSale>); 
begin 
    if Assigned(fSales) then 
    begin 
    fSales.OnNotify := fNotifySales; 
    fNotifySales := nil; 
    end; 

    fSales := Value; 

    if Assigned(fSales) then 
    begin 
    fNotifySales := fSales.OnNotify; 
    fSales.OnNotify := NotifySales; 
    end; 
end; 
+0

Gracias Stefan. Intenté su enfoque después de publicar esta pregunta y, aunque funciona como estaba intentado, creo que complica las cosas y encuentra que el enfoque de Nick es más simple y fácil de entender. Gracias por su respuesta, fui muy valioso para mi experimentación. –

Cuestiones relacionadas