簡體   English   中英

DDD,PHP。 域對象和業務邏輯

[英]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()。 我們在這里運行其他域對象。

也許我們應該只使用域對象來表示數據,但是使用一些裝飾器來執行更高級的任務?

提前致謝。

Domain Objects中應該存在多少業務邏輯? [...]我遇到過文章,我認為它應該盡可能小,只代表它的價值觀。

謹防幾乎完全由數據組成且缺乏行為的貧血領域模型 DDD是關於創建一個行為豐富的域模型。 因此,將邏輯添加到域類中是很好的。

DDD強調良好的面向對象設計,將方法和數據放在一起,從而促進高度凝聚的系統

我不確定這些問題是否有正確的答案,因為應用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM