Tabii ki, sızdıran soyutlamaların yasasını çağırabilir , ancak bu özellikle ilginç değildir, çünkü tüm soyutlamaların sızdıran bir durumdur. Bu kavrayışa karşı ve tartışılabilir, ancak soyutlama ile ne kastettiğimizi ve sızıntı ile ne kastettiğimizi anlamazsak bu işe yaramaz . Bu nedenle, önce bu terimlerin her birini nasıl gördüğümü anlatmaya çalışacağım:
Soyutlamalar
En sevdiğim soyutlama tanımı Robert C. Martin'in APPP'sinden türetildi :
"Bir soyutlama, temelin yükseltilmesi ve ilgisizliğin ortadan kaldırılmasıdır."
Dolayısıyla, arayüzler kendi başlarına soyutlama değildir . Onlar sadece önemli olan yüzeye çıkarırlar ve gerisini gizlerlerse soyutlamalardır.
sızdıran
Bağımlılık Enjeksiyonu Prensipleri, Desenler ve Uygulamaları kitabı , Bağımlılık Enjeksiyonu (DI) bağlamında sızdıran soyutlama terimini tanımlar . Bu bağlamda polimorfizm ve SOLID ilkeleri büyük rol oynamaktadır.
Gönderen Bağımlılık Inversion İlke (DIP) aşağıda belirtildiği tekrar APPP alıntı yaparak şöyle ki:
"istemciler [...] soyut arayüzlere sahipler"
Bunun anlamı, istemcilerin (çağrı kodu) gereksinim duydukları soyutlamaları tanımlamaları ve sonra da bu soyutlamayı uygulamanızdır.
Bir sızdıran soyutlama , bana göre, her nasılsa müşteri etmediğini bazı işlevleri dahil ederek DIP ihlal eden bir soyutlamadır gerek .
Senkron bağımlılıklar
Bir iş mantığı parçası uygulayan bir istemci, DI'yi genellikle veritabanları gibi belirli uygulama ayrıntılarından ayırmak için kullanır.
Bir restoran rezervasyonu isteğini işleyen bir etki alanı nesnesini düşünün:
public class MaîtreD : IMaîtreD
{
public MaîtreD(int capacity, IReservationsRepository repository)
{
Capacity = capacity;
Repository = repository;
}
public int Capacity { get; }
public IReservationsRepository Repository { get; }
public int? TryAccept(Reservation reservation)
{
var reservations = Repository.ReadReservations(reservation.Date);
int reservedSeats = reservations.Sum(r => r.Quantity);
if (Capacity < reservedSeats + reservation.Quantity)
return null;
reservation.IsAccepted = true;
return Repository.Create(reservation);
}
}
Burada, IReservationsRepository
bağımlılık sadece müşteri, MaîtreD
sınıf tarafından belirlenir :
public interface IReservationsRepository
{
Reservation[] ReadReservations(DateTimeOffset date);
int Create(Reservation reservation);
}
MaîtreD
Sınıfın eşzamansız olması gerekmediğinden bu arabirim tamamen eşzamanlıdır .
Asenkron bağımlılıklar
Arayüzü kolayca eşzamansız olacak şekilde değiştirebilirsiniz:
public interface IReservationsRepository
{
Task<Reservation[]> ReadReservations(DateTimeOffset date);
Task<int> Create(Reservation reservation);
}
MaîtreD
Sınıf Ancak gelmez gerek şimdi DIP ihlal edilmektedir, bu yöntemlerin asenkron olmak. Bunu sızdıran bir soyutlama olarak görüyorum, çünkü bir uygulama detayı müşteriyi değişmeye zorluyor. TryAccept
Yöntem şimdi de asenkron olmak zorundadır:
public async Task<int?> TryAccept(Reservation reservation)
{
var reservations =
await Repository.ReadReservations(reservation.Date);
int reservedSeats = reservations.Sum(r => r.Quantity);
if (Capacity < reservedSeats + reservation.Quantity)
return null;
reservation.IsAccepted = true;
return await Repository.Create(reservation);
}
Etki alanı mantığının eşzamansız olması için temel bir gerekçe yoktur, ancak uygulamanın eşzamansızlığını desteklemek için bu artık gereklidir.
Daha iyi seçenekler
NDC Sydney 2018'de bu konu hakkında bir konuşma yaptım . İçinde, sızıntı yapmayan bir alternatif de belirtiyorum. Bu konuşmayı 2019'da da birkaç konferansta vereceğim, ancak şimdi Async enjeksiyonunun yeni başlığıyla yeniden markalaştım .
Konuşmaya eşlik edecek bir dizi blog yayını da yayınlamayı planlıyorum. Bu makaleler zaten yazıldı ve makale kuyruğumda oturuyor, yayınlanmasını bekliyor, bu yüzden bizi izlemeye devam edin.