2012-04-26 3 views
5

Хорошо, я искал и не нашел подходящего решения для своей проблемы, я пересматриваю часть нашей системы продажи. Давайте предположим, что мы имеем следующие классы:Как создать классную зависимость, чтобы избежать Закона Деметры

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 текущего пользователя, а также я хочу суммировать суммы продажи «TotalSold» TWorkShift.

I've попробовал два различных подхода:

подход:

// Давайте предположим, что мы имеем рабочую смену с ID 1 и загружается из базы данных с: CurrentShift: = TWorkShift.Create (1);

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

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

Проблема с этим подходом является то, что подмигнули трудно проверить, потому что я хочу, чтобы инкапсулировать логику суммы в некоторых классах или где-либо еще (новый класс может быть?).

Подход B:

Мой другой подход в том числе, что код внутри самого класса TSale:

procedure TSale.Save; 
begin 
    SaveToDataBase; 

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

Этот подход, который я думаю, что нарушает закон Деметры и это не распространяется чувствовать себя мне ,

Я хочу найти «правильный путь», чтобы максимально упростить его и упростить обслуживание в будущем. Поэтому любые предложения будут оценены.

Благодаря

ответ

3

Если вы хотите добавить к продаже TWorkShift, то вы должны иметь

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

Другими словами, TWorkShift должны «спросить» за вещь он нуждается.

Кроме того, я не вижу причин, по которым TSale будет иметь поле TWorkShift. В Workshift есть много продаж, но почему у Sale есть WorkShift?

+0

Благодаря Ник, ну в этом случае я использую рамки Аврелий ORM так у меня есть «Ассоциация» для того, чтобы получить такую ​​информацию, как: 'Продажа: = Manager.Find (1); ShowMessage ('Продажа была продана в рабочей сменой с ID:' + IntToStr (Sale.Shift.ID)); ' Это необходимо, потому что иногда мне нужно показать всю информацию о продаже, такую ​​как смена, в которой она была продана, дата, кассир и т. Д. –

+1

Луис, это проблема для уровня представления а не BL. Уровень презентации должен собрать всю необходимую информацию. Таким образом, в вашем случае вы можете получить объект продажи из объекта workhift и получить всю информацию. – whosrdaddy

+0

Luis - если ORM заставляет вас это делать, вам, вероятно, стоит подумать об использовании другого ORM. Это плохой дизайн - Sale ничего не должен знать о Workshift, где это произошло. Что делать, если вы хотите вообще продать вещи от любой рабочей смены? –

0

Вы делаете что-то, когда добавляете предметы в TList, чтобы вы могли использовать OnNotify. Я не знаю, использует ли Aurelius это событие, поэтому я добавил для этого некоторый код. Вам нужно только увидеть, может ли назначить OnNotify внутри рамки после того, как список назначен вашему объекту TWorkShift, потому что тогда он может перезаписать обработчик событий 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

Спасибо Стефан. Я пробовал ваш подход после того, как я разместил этот вопрос, и, несмотря на то, что он работает как намеренный, я думаю, что это усложняет ситуацию и находит подход Ник более простым и понятным. Спасибо за ваш ответ, я был очень ценен для своих экспериментов. –

Смежные вопросы