1

Всякий раз, когда я читаю статью о современном шаблоне проектирования, например MVVM или DDD, мне трудно перевести этот пример в области, на которых я обычно работаю.Путь к доменной модели и бизнес-логике

Все эти шаблоны приходят к выводу о том, что модели домена должны существовать в их собственном маленьком пузыре, без каких-либо ссылок на что-либо, не должны подвергаться представлению о привязке, должны быть POCOs/POJO и содержать «бизнес-логику», ,

Вопрос, который я всегда задаю себе, заключается в следующем: что должна делать модель домена?

Ответ, очевидно, «Управлять бизнес-логикой», но когда я думаю о том, что может быть, у меня возникают проблемы с поиском реального мира примеров.

Например: Один типичный пример, который всегда появляется, - это финансовые приложения, где у вас может быть объект BankAccount, который может иметь функцию TransferMoneyTo(otherAccount). Это звучит неплохо в теории, но в реальном мире это приложение не будет управлять всеми банковскими счетами мира, а просто счетами одного банка. Поэтому приложение реального мира должно было бы как-то связаться с сервером другого банка, чтобы инициировать эту транзакцию. Это «как-то», очевидно, является услугой , которой не разрешено ссылаться на BankAccount. Это означает, что это не будет хорошим примером для изолированной модели домена.

До сих пор все примеры, которые я прочитал о том, где и как это, где пример работал только потому, что он пренебрегал важными деталями или тривиальными. Тривиальным я имею в виду, что «бизнес-логика» просто состояла из простой проверки (например, обязательных полей).

Все это приводит к anemic domain model (помимо проверки, возможно), которая должна быть плохой.

Мой вопрос: Что скрывает за термином «бизнес-логика» помимо проверки, что оправдывало бы необходимость в отдельной модели домена?

Примечание: Я знаю, это зависит от домена, над которым вы работаете, но я думаю, по крайней мере, какой-то пример, где DDD был бы действительно полезен, будет оценен.

+1

Я тоже несколько смутился, но затем наткнулся на эту замечательную статью. Может также помочь вам: http://www.codeproject.com/Articles/10746/Dude-where-s-my-business-logic – Guanxi

ответ

2

Что скрывается за термином «бизнес-логики»

Много моделей предметной области отражает бизнес-процессов и, таким образом, содержат государственные машины, где вы можете перейти вещи из известного действительного состояния в другое в соответствии с некоторыми правила. Вы получаете такой процесс практически в каждом бизнесе. Другие домены могут включать более сложные внутренние алгоритмы и преобразования данных.

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

Это «как-то», очевидно, сервис, к которому BankAccount не разрешено иметь ссылку на

Что касается доменов сообщающиеся с внешним миром, это на самом деле не их ответственность. Как правило, у вас есть домен, излучающий событие, говорящее «это случилось!». и прикладной контекст обрабатывает его и инициирует соответствующие связи с внешними системами.

Выполнение вызовов во внутренние и внешние подсистемы, чтобы потоки данных, вне и через приложение не являлись логикой домена, это проблема технического уровня приложения. Инверсия управления в той или иной форме (события, DI и т. Д.) Обычно является ключом к тому, что домен не знает об этом.

+0

Хорошо, если бы у вас был бы 'GetEmptySeatAtWindow (train)' и 'BookThisSeat (например, функция «место»), вероятно, будет какая-то нетривиальная логика. Хотя я бы не знал, где поставить эти функции в DDD, потому что этот класс должен будет знать все, что требуется для выполнения этих действий, потому что ему не разрешено извлекать дополнительные данные ... Процесс расчета налогов действительно выиграет от DDD. Я это вижу. Но это своего рода ниша. – Karsten

+0

Проблема, с которой я сталкиваюсь с этими событиями в домене, заключается в том, что я не знаю, как модель домена сохраняет себя в согласованном состоянии, если она не знает, что произошло в ответ на это событие. Например, «BankAccount» разрешается снимать деньги, только если принимающий банк принимает транзакцию. Если что-то пойдет не так, модель будет непоследовательна, и деньги исчезнут навсегда, если модель не знает о внешнем мире. – Karsten

+2

Ключом к DDD является создание понятий домена в вашем коде. У меня абсолютно нулевые знания в банковской сфере, но я думаю, вы бы моделировали это как два состояния: TransactionPending и TransactionCompleted. Домен остается в курсе изменений с помощью аппликативного слоя вокруг него. – guillaume31

0

У меня есть программное обеспечение футбол управления турнир, написанный на PHP (точно не вершина OOP),

Мой бизнес-логика включает в турнирной таблице калькулятор, который выясняет, какую позицию команда пришла на основе результатов своих игр , Стратегии разрыва связи могут быть немного задействованы. Другая бизнес-логика включает в себя планирование игр, назначение судей и координацию волонтеров.

Эта логика сидит в том, что я считаю слоем домена. Мои сущности сами (игры и т. Д.) Имеют тенденцию к анемии. Просто не так много для них, кроме данных об удержании. Но со мной все в порядке. Это классы обслуживания, в которых работает настоящая работа.

Я использую или ограниченный контекст и сводные корневые концепции. В состав моей игры входят команды, чиновники и поле. Когда я нахожусь в игровом контексте, тогда игра королева и отвечает за ее детей. В контексте управления полем поле является боссом, а игры - просто для езды.

Я достигаю независимости настойчивости. Я могу моделировать объекты домена и объекты значений, чтобы отражать требования к домену, не беспокоясь о том, в каких таблицах они будут находиться. Уровень ORM заботится о сопоставлении и позволяет мне хранить один доменный объект на нескольких таблицах или наоборот.

Дело в том, что выберете материал из DDD, который поможет вашим конкретным приложениям. Не беспокойтесь обо всем остальном.

0

Это «как-то», очевидно, сервис, к которому BankAccount не разрешено иметь ссылку. Это означает, что это не будет очень хорошим примером для изолированной модели домена.

В то время как BankAccount не имеет ссылки на себя для этой услуги, он все равно может взаимодействовать с такой услугой.

Для более простого примера возьмем расчет процентов. Наивный подход может быть:

Это плохо, потому что теперь у вас смешанные обязанности. Вычисление интереса не входит в круг класса BankAccount, и теперь оно связано с несколькими обязанностями, такими как вычисление, которое может меняться или зависеть от нескольких факторов.

public BankAccount 
{ 
    // private setters, so no one outside BankAccount can update it directly 
    public decimal Balance { get; private set; } 
    public AccountType AccountType { get; private set; } // assume business and private account 
    private public List<Transaction> transactions = new List<Transaction>(); 
    // return as "AsEnumerable" so user can't later cast it back to list and 
    // directly add Transactions, skipping the AddTransaction method 
    public IEnumerable<Transaction> Transactions { get { return transactions.AsEnumerable(); } } 

    public void CalculateInterest(IInterestCalculator calc) 
    { 
     decimal interest = calc.CalculateInterest(this); 
     this.AddTransaction(new Transaction() { Description = "Monthly Interest", Amount = interest }); 
    } 

    public void AddTransaction(Transaction transaction) 
    { 
     var newBalance = this.Balance + transaction.Balance; 

     if(this.transaction.Amount < 0 && newBalance < this.Limit) 
     { 
      // new balance would exceed the accounts limit 
      throw new NotEnoughFundsException(); 
     } 

     this.transactions.Add(transaction); 
     this.Balance = newAmount; 
    } 
} 

public interface IInterestCalculator 
{ 
    decimal CalculateInterest(Bankaccount); 
} 

public class DefaultAccountInterestCalculator : IInterestCalculator 
{ 
    public decimal CalculateInterest(BankAccount account) 
    { 
     // for sake of simplicity, inlined 
     return account.Balance * 0.02; 
    } 
} 
public class PremiumAccountInterestCalculator : IInterestCalculator 
{ 
    private const decimal Threshold = 10000m; 
    public decimal CalculateInterest(BankAccount account) 
    { 
     // Premium customers receive increased interest, above a certain threshold. 3% for the balance above the threshold of 10000 USD 
     if(account.Balance > Threshold) 
     { 
      return (decimal)((Threshold * 0.02) + (account.Balance-Threshold) * 0.03); 
     } 
     else 
     { 
      return (decimal)(account.Balance * 0.02); 
     } 
    } 
} 

В вашей службе с

BankAccount account = ...; 
IInterestCalculator calculator = (account.AccountType == AccountType.Premium)?new PremiumAccountInterestCalculator():DefaultAccountInterestCalculator(); 

BankAccount account.CalculateInterest(calculator); 

Теперь ваш BankAccount класс имеет только одну ответственность, сохраняя это состояние и бизнес-логику для этого требуется (т.е. проверить, достаточно ли баланс, только позволяет манипулировать банковский счет посредством методов, а не напрямую меняющихся Balance или для управления List<Transaction>.

И вычисление производится классами калькулятора, которые передаются в BankAccountCalculateInterest Метод. Служба содержит требуемую логику, которая не вписывается в калькулятор или класс BankAccount.

Итак, в целом: бизнес-логика (в модели с богатым доменом) - это вся логика, требуемая классу для поддержания его состояния и инкапсулировать его как можно больше. Во втором классе невозможно напрямую изменить баланс. Требуется либо AddTransaction, либо CalculateInterest (для расчета процентов).

Это гарантирует (при условии, что это одновременно безопасным), что Balance и Transactions всегда будет находиться в согласованном состоянии (т.е. никогда не хватает, чтобы добавить либо сделки или баланс обновления).

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