Aracılığıyla paylaş


Seedwork (etki alanı modeliniz için yeniden kullanılabilir kök sınıflar ve arabirimler)

İpucu

Bu içerik, .NET Docs'ta veya çevrimdışı olarak okunabilen ücretsiz indirilebilir bir PDF olarak sağlanan Kapsayıcılı .NET Uygulamaları için .NET Mikro Hizmet Mimarisi e-Kitabı'ndan bir alıntıdır.

.NET Microservices Architecture for Containerized .NET Applications eBook cover thumbnail.

Çözüm klasörü bir SeedWork klasörü içerir. Bu klasör, etki alanı varlıklarınız ve değer nesneleriniz için temel olarak kullanabileceğiniz özel temel sınıflar içerir. Bu temel sınıfları kullanarak her etki alanının nesne sınıfında yedekli koda sahip olmazsınız. Bu sınıf türlerinin klasörü, Framework gibi bir şey değil, SeedWork olarak adlandırılır. Buna SeedWork adı verilir çünkü klasör, gerçekten çerçeve olarak kabul edilemeyen yeniden kullanılabilir sınıfların yalnızca küçük bir alt kümesini içerir. Seedwork, Michael Feathers tarafından tanıtılan ve Martin Fowler tarafından popülerleştirilen bir terimdir, ancak bu klasörü Common, SharedKernel veya benzeri olarak adlandırabilirsiniz.

Şekil 7-12'de, etki alanı modelinin tohumunu oluşturan sınıflar, sıralama mikro hizmeti içinde gösterilmiştir. Entity, ValueObject ve Enumeration gibi birkaç özel temel sınıfın yanı sıra birkaç arabirimi vardır. Bu arabirimler (IRepository ve IUnitOfWork), altyapı katmanını uygulanması gerekenler hakkında bilgilendirir. Bu arabirimler, uygulama katmanından Bağımlılık Ekleme aracılığıyla da kullanılır.

Screenshot of the classes contained in the SeedWork folder.

Temel sınıfları ve arabirimleri içeren SeedWork klasörünün ayrıntılı içeriği: Entity.cs, Enumeration.cs, IAggregateRoot.cs, IRepository.cs, IUnitOfWork.cs ve ValueObject.cs.

Şekil 7-12. Örnek etki alanı modeli "seedwork" temel sınıfları ve arabirimleri kümesi

Bu, resmi bir çerçeve değil, birçok geliştiricinin projeler arasında paylaştığı kopyalama ve yapıştırma yeniden kullanımı türüdür. Herhangi bir katmanda veya kitaplıkta seedworks'leriniz olabilir. Ancak, sınıf ve arabirim kümesi yeterince genişlerse, tek bir sınıf kitaplığı oluşturmak isteyebilirsiniz.

Özel Varlık temel sınıfı

Aşağıdaki kod, varlık kimliği , eşitlik işleçleri, varlık başına etki alanı olay listesi gibi herhangi bir etki alanı varlığı tarafından aynı şekilde kullanılabilecek bir kod yerleştirebileceğiniz bir Varlık temel sınıfı örneğidir.

// COMPATIBLE WITH ENTITY FRAMEWORK CORE (1.1 and later)
public abstract class Entity
{
    int? _requestedHashCode;
    int _Id;
    private List<INotification> _domainEvents;
    public virtual int Id
    {
        get
        {
            return _Id;
        }
        protected set
        {
            _Id = value;
        }
    }

    public List<INotification> DomainEvents => _domainEvents;
    public void AddDomainEvent(INotification eventItem)
    {
        _domainEvents = _domainEvents ?? new List<INotification>();
        _domainEvents.Add(eventItem);
    }
    public void RemoveDomainEvent(INotification eventItem)
    {
        if (_domainEvents is null) return;
        _domainEvents.Remove(eventItem);
    }

    public bool IsTransient()
    {
        return this.Id == default(Int32);
    }

    public override bool Equals(object obj)
    {
        if (obj == null || !(obj is Entity))
            return false;
        if (Object.ReferenceEquals(this, obj))
            return true;
        if (this.GetType() != obj.GetType())
            return false;
        Entity item = (Entity)obj;
        if (item.IsTransient() || this.IsTransient())
            return false;
        else
            return item.Id == this.Id;
    }

    public override int GetHashCode()
    {
        if (!IsTransient())
        {
            if (!_requestedHashCode.HasValue)
                _requestedHashCode = this.Id.GetHashCode() ^ 31;
            // XOR for random distribution. See:
            // https://learn.microsoft.com/archive/blogs/ericlippert/guidelines-and-rules-for-gethashcode
            return _requestedHashCode.Value;
        }
        else
            return base.GetHashCode();
    }
    public static bool operator ==(Entity left, Entity right)
    {
        if (Object.Equals(left, null))
            return (Object.Equals(right, null));
        else
            return left.Equals(right);
    }
    public static bool operator !=(Entity left, Entity right)
    {
        return !(left == right);
    }
}

Varlık başına etki alanı olay listesi kullanan önceki kod, etki alanı olaylarına odaklanılırken sonraki bölümlerde açıklanacaktır.

Etki alanı modeli katmanındaki depo sözleşmeleri (arabirimler)

Depo sözleşmeleri, her toplama için kullanılacak depoların sözleşme gereksinimlerini ifade eden .NET arabirimleridir.

EF Core kodu veya diğer altyapı bağımlılıkları ve koduyla (Linq, SQL vb.) depoların kendileri etki alanı modeli içinde uygulanmamalıdır; depoları yalnızca etki alanı modelinde tanımladığınız arabirimleri uygulamalıdır.

Bu uygulamayla ilgili bir düzen (depo arabirimlerinin etki alanı modeli katmanına yerleştirilmesi) Ayrılmış Arabirim desenidir. Martin Fowler tarafından açıklandığı gibi, "Bir pakette bir arabirim tanımlamak ancak başka bir pakette uygulamak için Ayrılmış Arabirim'i kullanın. Bu şekilde, arabirime bağımlı olması gereken bir istemci, uygulamadan tamamen haberdar olmayabilir."

Ayrılmış Arabirim deseninin uygulanması, uygulama katmanının (bu örnekte mikro hizmet için Web API projesi) etki alanı modelinde tanımlanan gereksinimlere bağımlılığı olmasını sağlar, ancak altyapı/kalıcılık katmanına doğrudan bağımlılık sağlamaz. Ayrıca, depolar kullanılarak altyapı/kalıcılık katmanında uygulanan uygulamayı yalıtmak için Bağımlılık Ekleme'yi kullanabilirsiniz.

Örneğin, IOrderRepository arabirimine sahip aşağıdaki örnek, OrderRepository sınıfının altyapı katmanında hangi işlemleri gerçekleştirmesi gerektiğini tanımlar. Uygulamanın geçerli uygulamasında, sorguların basitleştirilmiş CQRS yaklaşımına göre bölünmesi nedeniyle kodun veritabanına sipariş eklemesi veya güncelleştirmesi gerekir.

// Defined at IOrderRepository.cs
public interface IOrderRepository : IRepository<Order>
{
    Order Add(Order order);

    void Update(Order order);

    Task<Order> GetAsync(int orderId);
}

// Defined at IRepository.cs (Part of the Domain Seedwork)
public interface IRepository<T> where T : IAggregateRoot
{
    IUnitOfWork UnitOfWork { get; }
}

Ek kaynaklar