OOP topluluğunda, sınıf oluşturucunun bir nesneyi kısmen veya tamamen başlatılmamış bırakması konusunda yaygın bir anlaşma olduğu görülmektedir.
"Başlatma" ile ne demek istiyorum? Kabaca söylemek gerekirse, yeni oluşturulan bir nesneyi tüm sınıf değişmezlerinin sahip olduğu bir duruma getiren atomik süreç. Bir nesnede gerçekleşen ilk şey olmalı (her nesne için yalnızca bir kez çalıştırılmalıdır) ve başlatılmamış bir nesneyi ele geçirmesine izin verilmemelidir. (Bu nedenle, sınıf yapıcısında nesne başlatma işlemini gerçekleştirmek için sık sık tavsiye edilir. Aynı nedenden ötürü,
Initialize
bunlar genellikle atomikliği parçaladığı ve henüz olmayan bir nesneyi elde etmeyi ve kullanmayı mümkün kıldığından , yöntemler genellikle kaşlarını çatar. iyi tanımlanmış bir durumda.)
Sorun: CQRS, bir nesnenin tüm durum değişikliklerinin sıralı bir olay serisine (olay akışı) yakalandığı olay kaynağı (CQRS + ES) ile birleştirildiğinde, bir nesnenin gerçekten tamamen başlatılmış bir duruma ulaştığını merak ediyorum: Sınıf yapıcısının sonunda mı yoksa nesneye ilk olay uygulandıktan sonra mı?
Not: "Toplam kök" terimini kullanmaktan kaçınıyorum. İsterseniz, "nesne" yi her okuduğunuzda değiştirin.
Tartışma örneği: Her nesnenin bazı opak Id
değerlerle benzersiz bir şekilde tanımlandığını varsayın (GUID düşünün). Bu nesnenin durum değişikliklerini temsil eden bir olay akışı, olay deposunda aynı Id
değerle tanımlanabilir: (Doğru olay sırası konusunda endişelenmeyelim.)
interface IEventStore
{
IEnumerable<IEvent> GetEventsOfObject(Id objectId);
}
Ayrıca iki nesne türü olduğunu Customer
ve varsayalım ShoppingCart
. Şunlara odaklanalım ShoppingCart
: Oluşturulduğunda, alışveriş sepetleri boştur ve tam olarak bir müşteriyle ilişkilendirilmelidir. Bu son bit bir sınıf değişmezidir: a ile ShoppingCart
ilişkili olmayan bir nesne Customer
geçersiz bir durumda.
Geleneksel OOP'de, bunu yapıcıda modelleyebilir:
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;
}
}
Ancak ertelenmiş başlatma ile bitmeden bu CQRS + ES modelleme kaybı var. Bu basit başlatma biti etkin bir şekilde devlet değişikliği olduğundan, bir olay olarak modellenmesi gerekmez mi ?:
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.
Bunun, herhangi bir ShoppingCart
nesnenin olay akışındaki ilk olay olması gerektiği açıktır ve bu nesne yalnızca olay kendisine uygulandıktan sonra başlatılır.
Bu yüzden başlatma, olay akışının "playback" (bir Customer
nesne veya ShoppingCart
nesne veya bu konu için herhangi bir nesne türü için aynı çalışacak çok genel bir işlem) parçası haline gelirse ...
- Yapıcı parametresiz olmalı ve hiçbir şey yapmamalı, tüm işleri bir
void Apply(CreatedEmptyShoppingCart)
yönteme bırakmalıdır (kaşlarını çatmış olanla aynıdırInitialize()
)? - Ya da kurucu bir olay akışı almalı ve oynatmalı mı (yeniden başlatma atomunu tekrar yapar, ama her sınıfın yapıcısının aynı genel "oynat ve uygula" mantığını, yani istenmeyen kod çoğaltmasını içerdiği anlamına gelir)?
- Düzgün nesnesini başlatır ki (yukarıda gösterildiği gibi) ve Ya da her ikisi geleneksel cepten yapıcı olmalıdır sonra tüm olayları ancak ilk olan
void Apply(…)
kendisine -ied?
Tam çalışan bir demo uygulaması sağlamak için cevap beklemiyorum; Birisi benim akıl kusurlu veya nesne başlatma gerçekten olup olmadığını nerede açıklayabilir ben zaten çok mutlu olurum olan en CQRS + ES uygulamalarda bir "acı noktası".
Initialize
yöntemi) işgal edecekleri aynı yeri alıyor gibi görünüyor . Bu beni şu soruya götürüyor, böyle bir fabrikanız neye benzeyebilir?