Dường như có một thỏa thuận rộng rãi trong cộng đồng OOP rằng trình xây dựng lớp không nên để một đối tượng hoặc thậm chí hoàn toàn không được khởi tạo.
"Khởi tạo" nghĩa là gì? Nói một cách đơn giản, quá trình nguyên tử đưa một vật thể mới được tạo ra vào trạng thái mà tất cả các bất biến lớp của nó giữ. Nó phải là điều đầu tiên xảy ra với một đối tượng, (nó chỉ nên chạy một lần cho mỗi đối tượng) và không có gì được phép giữ một đối tượng chưa được khởi tạo. (Do đó, lời khuyên thường xuyên để thực hiện khởi tạo đối tượng ngay trong hàm tạo của lớp. Vì lý do tương tự,
Initialize
các phương thức thường được tán thành, vì chúng phá vỡ tính nguyên tử và làm cho nó có thể nắm giữ và sử dụng một đối tượng chưa ở trạng thái được xác định rõ.)
Vấn đề: Khi CQRS được kết hợp với tìm nguồn cung ứng sự kiện (CQRS + ES), trong đó tất cả các thay đổi trạng thái của một đối tượng được bắt gặp trong một chuỗi các sự kiện (luồng sự kiện), tôi sẽ tự hỏi khi một đối tượng thực sự đạt đến trạng thái khởi tạo hoàn toàn: Vào cuối của trình xây dựng lớp, hoặc sau khi sự kiện đầu tiên đã được áp dụng cho đối tượng?
Lưu ý: Tôi không sử dụng thuật ngữ "tổng hợp gốc". Nếu bạn thích, thay thế nó bất cứ khi nào bạn đọc "đối tượng".
Ví dụ cho thảo luận: Giả sử rằng mỗi đối tượng được xác định duy nhất bởi một số Id
giá trị mờ (nghĩ GUID). Một luồng sự kiện thể hiện các thay đổi trạng thái của đối tượng đó có thể được xác định trong kho sự kiện theo cùng một Id
giá trị: (Chúng ta đừng lo lắng về thứ tự sự kiện chính xác.)
interface IEventStore
{
IEnumerable<IEvent> GetEventsOfObject(Id objectId);
}
Giả sử thêm rằng có hai loại đối tượng Customer
và ShoppingCart
. Hãy tập trung vào ShoppingCart
: Khi được tạo, giỏ mua hàng trống và phải được liên kết với chính xác một khách hàng. Bit cuối cùng đó là một bất biến lớp: Một ShoppingCart
đối tượng không liên quan đến a Customer
đang ở trạng thái không hợp lệ.
Trong OOP truyền thống, người ta có thể mô hình hóa điều này trong hàm tạo:
partial class ShoppingCart
{
public Id Id { get; private set; }
public Customer Customer { get; private set; }
public ShoppingCart(Id id, Customer customer)
{
this.Id = id;
this.Customer = customer;
}
}
Tuy nhiên, tôi không biết làm thế nào để mô hình hóa điều này trong CQRS + ES mà không kết thúc với việc khởi tạo hoãn lại. Vì một chút khởi tạo đơn giản này thực sự là một sự thay đổi trạng thái, nên nó có phải được mô hình hóa như một sự kiện không?
partial class CreatedEmptyShoppingCart
{
public ShoppingCartId { get; private set; }
public CustomerId { get; private set; }
}
// Note: `ShoppingCartId` is not actually required, since that Id must be
// known in advance in order to fetch the event stream from the event store.
Đây rõ ràng sẽ phải là sự kiện đầu tiên trong ShoppingCart
luồng sự kiện của bất kỳ đối tượng nào và đối tượng đó sẽ chỉ được khởi tạo khi sự kiện được áp dụng cho sự kiện đó.
Vì vậy, nếu khởi tạo trở thành một phần của "phát lại" luồng sự kiện (đây là một quá trình rất chung chung có thể sẽ hoạt động như nhau, cho dù Customer
đối tượng hay ShoppingCart
đối tượng hoặc bất kỳ loại đối tượng nào khác cho vấn đề đó)
- Hàm tạo có nên không tham số và không làm gì cả, để lại tất cả công việc cho một
void Apply(CreatedEmptyShoppingCart)
phương thức nào đó (giống như phương pháp nhăn mặtInitialize()
)? - Hoặc hàm tạo nên nhận một luồng sự kiện và phát lại (điều này làm cho việc khởi tạo lại nguyên tử, nhưng có nghĩa là hàm tạo của mỗi lớp chứa cùng một logic "phát lại và áp dụng" chung, tức là sao chép mã không mong muốn)?
- Hoặc nên có cả một hàm tạo OOP truyền thống (như được hiển thị ở trên) để khởi tạo đúng đối tượng, và sau đó tất cả các sự kiện nhưng lần đầu tiên được
void Apply(…)
liên kết với nó?
Tôi không mong đợi câu trả lời để cung cấp một triển khai demo hoạt động đầy đủ; Tôi đã rất vui nếu ai đó có thể giải thích lý do của tôi thiếu sót ở đâu, hoặc liệu khởi tạo đối tượng có thực sự là một "điểm đau" trong hầu hết các triển khai CQRS + ES hay không.
Initialize
phương thức) sẽ chiếm giữ. Điều đó dẫn tôi đến câu hỏi, một nhà máy của bạn trông như thế nào?