Man kann sich natürlich auf das Gesetz der undichten Abstraktionen berufen , aber das ist nicht besonders interessant, da es davon ausgeht, dass alle Abstraktionen undicht sind. Man kann für und gegen diese Vermutung argumentieren, aber es hilft nicht, wenn wir nicht verstehen, was wir unter Abstraktion verstehen und was wir unter undicht verstehen . Daher werde ich zunächst versuchen zu beschreiben, wie ich jeden dieser Begriffe betrachte:
Abstraktionen
Meine Lieblingsdefinition von Abstraktionen leitet sich aus der APPP von Robert C. Martin ab :
"Eine Abstraktion ist die Verstärkung des Wesentlichen und die Beseitigung des Irrelevanten."
Somit Schnittstellen sind nicht in sich selbst, Abstraktionen . Sie sind nur dann Abstraktionen, wenn sie das Wesentliche an die Oberfläche bringen und den Rest verbergen.
Undicht
Das Buch Prinzipien, Muster und Praktiken der Abhängigkeitsinjektion definiert den Begriff undichte Abstraktion im Kontext der Abhängigkeitsinjektion (DI). Polymorphismus und die SOLID-Prinzipien spielen in diesem Zusammenhang eine große Rolle.
Aus dem Dependency Inversion Principle (DIP) folgt unter erneuter Angabe von APPP:
"Kunden besitzen [...] die abstrakten Schnittstellen"
Dies bedeutet, dass Clients (aufrufender Code) die erforderlichen Abstraktionen definieren und Sie diese Abstraktion dann implementieren.
Eine undichte Abstraktion ist meiner Ansicht nach eine Abstraktion, die gegen das DIP verstößt, indem sie einige Funktionen enthält, die der Client nicht benötigt .
Synchrone Abhängigkeiten
Ein Client, der eine Geschäftslogik implementiert, verwendet DI normalerweise, um sich von bestimmten Implementierungsdetails zu entkoppeln, z. B. von Datenbanken.
Stellen Sie sich ein Domain-Objekt vor, das eine Anfrage für eine Restaurantreservierung bearbeitet:
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);
}
}
Hier wird die IReservationsRepository
Abhängigkeit ausschließlich vom Client, der MaîtreD
Klasse, bestimmt:
public interface IReservationsRepository
{
Reservation[] ReadReservations(DateTimeOffset date);
int Create(Reservation reservation);
}
Diese Schnittstelle ist vollständig synchron, da die MaîtreD
Klasse sie nicht asynchron benötigen muss.
Asynchrone Abhängigkeiten
Sie können die Schnittstelle einfach so ändern, dass sie asynchron ist:
public interface IReservationsRepository
{
Task<Reservation[]> ReadReservations(DateTimeOffset date);
Task<int> Create(Reservation reservation);
}
Die MaîtreD
Klasse benötigt diese Methoden jedoch nicht , um asynchron zu sein, sodass jetzt das DIP verletzt wird. Ich halte dies für eine undichte Abstraktion, da ein Implementierungsdetail den Client zu Änderungen zwingt. Die TryAccept
Methode muss nun auch asynchron werden:
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);
}
Es gibt keine inhärente Begründung dafür, dass die Domänenlogik asynchron ist. Um jedoch die Asynchronität der Implementierung zu unterstützen, ist dies jetzt erforderlich.
Bessere Optionen
Auf der NDC Sydney 2018 hielt ich einen Vortrag zu diesem Thema . Darin skizziere ich auch eine Alternative, die nicht leckt. Ich werde diesen Vortrag auch 2019 auf mehreren Konferenzen halten, aber jetzt mit dem neuen Titel Async Injection umbenannt .
Ich plane, auch eine Reihe von Blog-Posts zu veröffentlichen, um den Vortrag zu begleiten. Diese Artikel sind bereits geschrieben und befinden sich in meiner Artikelwarteschlange und warten darauf, veröffentlicht zu werden. Bleiben Sie also auf dem Laufenden.