比SOLID更重要的與DDD設計相關的GRASP原則 - Kamil Grzybek

banq發表於2019-09-05

我最近注意到很多注意力都集中在SOLID原則上。這是非常好的事情,因為它是物件導向設計(OOD)和程式設計的總體基礎。對於面嚮物件語言的開發人員,SOLID原則的知識是編寫具有良好質量特徵的程式碼的要求。關於這些規則有很多文章和課程,所以如果你還不瞭解它們,請儘快學習。

另一方面,關於物件導向程式設計還有另一個不太為人所知的規則。它被稱為GRASP - 一般責任分配軟體模式(或原則)。網際網路上關於這個主題的材料要少得多,所以我決定把它拉得更近,因為我認為其中描述的原則和SOLID原則一樣重要。

免責宣告:這篇文章的靈感源自Craig Larman的書:應用UML和模式:物件導向的分析和設計以及迭代開發簡介。雖然上一版本是在2004年釋出的,但據我所知,這本書仍然是最新的,並且完美地解釋瞭如何使用面嚮物件語言設計系統。相信我,很難找到關於這個主題的更好的書。它不是關於UML的書,但你可以從中學習UML,因為它也很好解釋。每個開發者必須擁有的時間段。

軟體職責責任

軟體責任是一個非常重要的概念,不僅涉及類,還涉及模組和整個系統。在責任方面進行思考是考慮軟體設計的流行方式。我們總是可以提出以下問題:

  • - 這個類/模組/元件/系統的責任是什麼?
  • -它是負責這個實現功能還是負責的那個功能實現?
  • - 在這種特定背景下是否違反了單一責任原則?

但是,為了回答這些型別的問題,我們應該問一個更根本的問題:職責責任是什麼意思,什麼是在軟體的情況下的責任?

做和知道

正如Rebecca Wirfs-Brock物件設計中所提出的:角色,責任和合作書和她的RDD方法的責任是:

履行任務或瞭解資訊的義務

正如我們從這個定義中看到的,我們在這裡明確區分了行為(做)和資料(知道)。

物件職責責任被視為:

  • a)自己做某事 - 建立物件,處理資料,做一些計算/計算
  • b)啟動和協調與其他物件的動作

物件的責任可以定義為:

  • a)私有和公共物件資料
  • b)相關物件引用
  • c)它可以派生的東西

我們來看一個例子:

public class Customer : 
Entity,  // knowing  這屬於知道
IAggregateRoot  // knowing 繼承聚合根屬於知道
{
    public Guid Id { get; private set; } // knowing

    public string Email { get; private set; } // knowing

    public string Name { get; private set; } // knowing

    private readonly List<Order> _orders; // knowing

    private Customer()
    {
        this._orders = new List<Order>();
    }

    // doing something itself 這屬於做某些事情
    public Customer(string email, string name, ICustomerUniquenessChecker customerUniquenessChecker)
    {
        this.Email = email;
        this.Name = name;

        // doing - initiate and coordinate actions with other objects
        var isUnique = customerUniquenessChecker.IsUnique(this); 
        if (!isUnique)
        {
            throw new BusinessRuleValidationException("Customer with this email already exists.");
        }

        this.AddDomainEvent(new CustomerRegisteredEvent(this));
    }
    
    // doing something itself
    public void AddOrder(Order order)
    {
        // doing - initiate and coordinate actions with other objects
        if (this._orders.Count(x => x.IsOrderedToday()) >= 2) 
        {
            throw new BusinessRuleValidationException("You cannot order more than 2 orders on the same day");
        }

        this._orders.Add(order);

        this.AddDomainEvent(new OrderAddedEvent(order));
    }

    // doing something itself
    public void ChangeOrder(
        Guid orderId, 
        List<OrderProduct> products,
        List<ConversionRate> conversionRates)
    {
        var order = this._orders.Single(x => x.Id == orderId);
        
        // doing - initiate and coordinate actions with other objects
        order.Change(products, conversionRates); 

        this.AddDomainEvent(new OrderChangedEvent(order));
    }

    // doing something itself
    public void RemoveOrder(Guid orderId)
    {
        var order = this._orders.Single(x => x.Id == orderId);
        
        // doing - initiate and coordinate actions with other objects
        order.Remove(); 

        this.AddDomainEvent(new OrderRemovedEvent(order));
    }
    
    // doing something itself
    public GetOrdersTotal(Guid orderId) 
    {
        return this._orders.Sum(x => x.Value);
    }
}

如果您想了解有關軟體職責的更多資訊並深入瞭解責任職責驅動設計,您可以直接從Rebecca的Wirfs-Brock書籍或本PDF中閱讀

好的,現在我們知道軟體背景下的責任是什麼。讓我們看看如何使用GRASP分配此職責。

GRASP

GRASP是 General Responsibility Assignment Software Patterns的簡稱,物件責任的分配是OOD的關鍵技能之一。每個程式設計師和設計師都應該熟悉這些模式,更重要的是 - 知道如何在日常工作中應用它們(順便說一下 - 相同的假設應該適用於SOLID原則)。

這是9種GRASP模式的列表(有時稱為原則,但請不要專注於此處的命名):

  1. 資訊專家
  2. 建立者
  3. 控制器
  4. 低耦合
  5. 高內聚
  6. 間接
  7. 多型
  8. 純粹製造
  9. 受保護的變化

 

相關文章