[英]DDD, PHP. Domain Object and Business Logic
我最近一直忙於嘗試理解ddd和Model層的概念。 閱讀大量的文章,例子,Q和A,花了很多時間。 而且我仍然不確定我是否有正確的原則。
其中之一就是問題的答案:Domain Objects中應該存在多少業務邏輯? 有些消息來源說Domain Objects應該附帶整個業務邏輯,另一方面,我遇到了一些文章,我認為它應該盡可能小,只能代表它的價值。 這讓我很困惑。
在我的理解中,域對象是表示域中實體的類。
因此,舉例來說,請使用Invoice實體。 每張發票都包含其項目。 要計算發票金額,我們必須對所有項目值進行求和(這是非常簡單的示例,在現實世界中會出現添加稅,計算付費價值等情況)
class Invoice
{
public $id;
public $items = [];
public $status;
const STATUS_PAID = 'paid';
const STATUS_NOT_PAID = 'not_paid';
public function isPaid()
{
return $this->status == self::STATUS_PAID;
}
public function getInvoiceValue()
{
$sum = 0;
foreach($this->items as $item) {
$sum += $item->value;
}
return $sum;
}
}
在我的理解中,方法isPaid()是在正確的位置。 它指的是自己的數據。 但我不確定getInvoiceValue()。 我們在這里運行其他域對象。
也許我們應該只使用域對象來表示數據,但是使用一些裝飾器來執行更高級的任務?
提前致謝。
我不確定這些問題是否有正確的答案,因為應用DDD實際上取決於您正在應用它的特定域。 如果滿足業務需求,有些地方您的實施可能完全有效。 在其他人中,就像你提到的稅收等,它不會。 因此,我要說您需要不斷詢問有關您的域名的問題,以便在將其轉換為代碼之前完全了解您的需求。
話雖如此,如果您有一個更復雜的場景,需要一些額外的外部世界知識來提出發票的價值,一個選項是明確地在您的域中表示。 在您的示例中,可以是InvoiceProducer,它可以具有以下簽名:
class InvoiceProducer {
public function __construct(TaxProvider $taxProvider) {
$this->taxProvider = $taxProvider;
}
public function invoiceFor(array $items) {
new Invoice($items, $this->calculateValue($items));
}
private function calculateValue(array $items) {
$sum = array_reduce($items, function($acc, $item){
$acc += $item->value;
}
return $this->taxProvider->applyTaxTo($sum);
}
}
另一個選擇是使用某種策略模式,這將使您的實現與現在的方式非常相似,但是您可以按照您希望計算稅收的方式傳遞您的調用:
public function getInvoiceValue(TaxProvider $taxProvider)
{
$sum = 0;
foreach($this->items as $item) {
$sum += $item->value;
}
return $taxProvider->applyTaxFor($sum);
}
同樣,它實際上取決於您的特定域的工作方式,但正如您所看到的,實現不應該是那么大的交易。 更多關於它如何適合您的域名。
Domain Objects中應該存在多少業務邏輯?
所有這些(如果可能的話)。 DDD的目的是捕獲域中的業務邏輯 - 這里可以使用各種戰術模式來幫助(聚合,實體,值對象,域服務等......)。
域對象是表示域中實體的類。
您域中的類可以代表的不僅僅是實體。 聚合,實體,值對象,域服務等都可以由域中的類表示。
但我不確定getInvoiceValue()。 我們在這里運行其他域對象。
您給Invoice的示例是Aggregate的典型示例 - Invoice將包含InvoiceItems。 getInvoiceValue()在這里很好。
在我們的例子中,Invoice是一個聚合。 Aggregate Root是Invoice本身,但它也是Entity,對吧? 它有自己的身份(發票號是唯一的)。
是,對的
什么是InvoiceItems呢? 我可以直接從InvoiceItem存儲庫中獲取它們(如果我應該創建它),還是我總是只需要在Aggregate上運行?
這取決於您的使用案例。 它有助於將寫入和讀取模型分開(CQRS)。 如果您正在談論讀取方(即報告),那么您繞過域模型並擁有代表您的讀取模型的對象。 這可能只是一個數據庫查詢。 如果您正在談論您的寫入方(即命令,域),那么通常每個聚合根都有一個存儲庫。 你的聚合根源是一個建模問題。 您希望以強制執行所有業務規則的方式創建它們 - 在您的示例中,如果發票需要加載InvoiceItems以強制執行規則(例如,“每個發票不超過5個項目”)則是,它們應該是通過聚合根加載
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.