5 Stimmen

Wie man die Klassenabhängigkeit gestaltet, um das Gesetz von Demeter zu vermeiden

Ok, ich habe gesucht und konnte keine passende Lösung für mein Problem finden, ich bin dabei, einen Teil unseres Kassensystems neu zu gestalten. Nehmen wir an, wir haben die folgenden Klassen:

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;

Das Problem, vor dem ich stehe, ist, die beste Idee zu finden, ohne gegen das Gesetz der Demeter zu verstoßen. Was ich zu erreichen versuche, ist Folgendes:

  1. Jedes Mal, wenn ein neuer TSale gespeichert wird, möchte ich ihn zur Verkaufsliste der TWorkShift des aktuellen Benutzers hinzufügen, und außerdem möchte ich den Betrag des Verkaufs zum "TotalSold" der TWorkShift addieren.

Ich habe zwei verschiedene Ansätze ausprobiert:

Ansatz A:

// Nehmen wir an, wir haben eine Arbeitsschicht mit der ID 1 und wird aus der Datenbank geladen mit: CurrentShift := TWorkShift.Create(1);

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

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

Das Problem bei diesem Ansatz ist, dass es schwierig ist, zu testen, weil ich die Logik der Summe in einigen der Klassen oder irgendwo anders (eine neue Klasse vielleicht?) kapseln möchte.

Ansatz B:

Mein anderer Ansatz ist, diesen Code in die TSale-Klasse selbst aufzunehmen:

procedure TSale.Save;
begin
    SaveToDataBase; 

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

Dieser Ansatz verstößt meiner Meinung nach gegen das Gesetz der Demeter und fühlt sich für mich nicht richtig an.

Ich möchte einen "richtigen Weg" finden, um es zu tun Maximierung Code Einfachheit und einfache Wartung in der Zukunft. Also jede Anregung würde geschätzt werden.

Danke

3voto

Nick Hodges Punkte 16331

Wenn Sie einen Verkauf zu TWorkShift hinzufügen möchten, sollten Sie über

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

Mit anderen Worten: TWorkShift sollte nach dem, was es braucht, "fragen".

Ich sehe auch keinen Grund, warum TSale ein TWorkShift-Feld haben sollte. Ein Workshift hat viele Verkäufe, aber warum sollte ein Sale einen WorkShift haben?

0voto

Stefan Glienke Punkte 19667

Sie tun etwas, wenn Sie Elemente zu einer TList hinzufügen, so dass Sie die OnNotify verwenden können. Ich weiß nicht, ob Aurelius auch dieses Ereignis verwendet, also habe ich etwas Code dafür hinzugefügt. Sie müssen nur sehen, ob die Zuweisung von OnNotify innerhalb des Frameworks erfolgen kann, nachdem die Liste Ihrem TWorkShift-Objekt zugewiesen wurde, denn dann könnte es den NotifySales-Eventhandler überschreiben.

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;

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X