2012-04-26 38 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