2012-04-26 63 views
5

好吧,我已经搜索过,无法找到适合我的问题的解决方案,我正在重新设计我们的销售点系统的一部分。 Let's假设我们有以下类:现在如何设计阶级依赖性试图避免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; 

,我面临的问题是试图来最好的主意,不违反迪米特法则。我试图做到的是以下几点:

  1. 新TSale保存我想将它添加到当前用户的TWorkShift的销售清单,也是我要总结的量每次出售给TWorkShift的“TotalSold”。

从来就尝试两种不同的方法:

解决方法A:

// Let's假设我们有与ID 1工作转变,会从数据库加载: CurrentShift:= TWorkShift.Create(1);

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

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

这种方法的问题是,It's难以测试,因为我想封装和的逻辑在一些类或其他地方的(一类新的可能?)。

方法B:

我的另一种方法是,包括TSale类本身内部的代码:

procedure TSale.Save; 
begin 
    SaveToDataBase; 

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

这种方法我认为违反迪米特法则和doesn't觉得我的权利。

我想要找到一个“正确的方法”来做到最大限度地简化代码和简化维护。所以任何建议,将不胜感激。

感谢

回答

3

如果你想添加一个出售给TWorkShift,那么你应该有

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

换句话说,TWorkShift应该“问”它需要的东西。

此外,我没有看到TSale会有TWorkShift字段的任何理由。轮班有很多销售,但为什么销售有一个WorkShift?

+0

感谢尼克,那么在这种情况下,我使用的是奥勒留ORM框架,所以我有一个“协会”,以获取信息,例如: '销售:= Manager.Find (1); ShowMessage('销售在ID为'+ IntToStr(Sale.Shift)的工作班次中出售。ID));' 这是必要的,因为有时我需要显示有关销售的所有信息,例如销售时间,日期,收银员等。 – 2012-04-27 00:12:33

+1

Luis,这是表示层的问题不是BL。表示层应该汇集所有需要的信息。因此,在您的情况下,您可以从轮班对象中检索销售对象并获取所有信息。 – whosrdaddy 2012-04-27 09:05:08

+0

Luis - 如果ORM迫使你这么做,那么你可能需要考虑使用不同的ORM。这是不好的设计 - 一个销售应该对发生的事情一无所知。如果你想把所有的工作转移出去,怎么办? – 2012-04-28 02:04:50

0

当您将项目添加到TList以便您可以使用OnNotify时,您正在做某些事情。 我不知道Aurelius是否也在使用该事件,因此我为此添加了一些代码。在将列表分配给TWorkShift对象之后,您只需查看赋予OnNotify是否可以在框架内发生,因为那样它可能会覆盖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

谢谢Stefan。在我发布这个问题后,我尝试了你的方法,尽管它按照预期工作,但我认为它使事情复杂化,并发现Nick的方法更简单,更易于理解。感谢您的回答,我对我的实验非常有价值。 – 2012-04-28 05:21:51