물론 누설 추상화 의 법칙을 부를 수는 있지만 모든 추상화가 누설된다는 점에서 특히 흥미롭지는 않습니다. 우리는 그 추측을 반대 할 수 있지만 , 추상화 에 의해 우리가 의미하는 것과 누설에 의해 의미하는 것을 이해하지 못한다면 도움이되지 않습니다 . 따라서 먼저 이러한 각 용어를 어떻게 보는지 설명하려고합니다.
추상화
내가 가장 좋아하는 추상화 정의는 Robert C. Martin의 APPP 에서 파생되었습니다 .
"추상화는 필수의 증폭과 관련성이없는 제거입니다."
따라서 인터페이스 자체는 추상화가 아닙니다 . 그들은 중요한 것을 표면에 가져오고 나머지를 숨기면 추상화 일뿐입니다.
새는
Dependency Injection Principles, Patterns and Practices 책 은 DI (Dependency Injection)의 맥락에서 누출 추상 이라는 용어를 정의합니다 . 이러한 맥락에서 다형성과 SOLID 원칙이 큰 역할을합니다.
로부터 의존 관계 역전 원칙 (DIP)가 다음 다시 APPP을 인용, 다음, 그 :
"클라이언트 [...]는 추상 인터페이스를 소유합니다"
이것이 의미하는 것은 클라이언트 (호출 코드)가 필요한 추상화를 정의한 다음 해당 추상화를 구현한다는 것입니다.
제 생각에 누설 되는 추상화는 클라이언트가 필요로 하지 않는 기능을 포함하여 DIP를 위반하는 추상화입니다 .
동기 종속성
비즈니스 로직을 구현하는 클라이언트는 일반적으로 DI를 사용하여 일반적으로 데이터베이스와 같은 특정 구현 세부 사항과 분리됩니다.
식당 예약 요청을 처리하는 도메인 객체를 고려하십시오.
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);
}
}
여기서 IReservationsRepository
종속성은 클라이언트 클래스에 의해 독점적 으로 결정 됩니다 MaîtreD
.
public interface IReservationsRepository
{
Reservation[] ReadReservations(DateTimeOffset date);
int Create(Reservation reservation);
}
이 인터페이스는 MaîtreD
클래스가 비동기식 일 필요 가 없으므로 완전히 동기식 입니다.
비동기 종속성
인터페이스를 비동기식으로 쉽게 변경할 수 있습니다.
public interface IReservationsRepository
{
Task<Reservation[]> ReadReservations(DateTimeOffset date);
Task<int> Create(Reservation reservation);
}
그러나 MaîtreD
클래스 는 이러한 메소드가 비동기식 일 필요가 없으므로 이제 DIP가 위반됩니다. 구현 세부 사항으로 인해 클라이언트가 변경되기 때문에 이것이 누설되는 추상화라고 생각합니다. 이 TryAccept
방법은 이제 비동기식이어야합니다.
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);
}
도메인 로직이 비동기 적이라는 근본적인 근거는 없지만 구현의 비동기 성을 지원하기 위해서는 이제 이것이 필요합니다.
더 나은 옵션
NDC 시드니 2018 에서이 주제에 대해 이야기했습니다 . 또한 누출되지 않는 대안을 설명합니다. 2019 년에도 여러 회의에서이 강연을 할 예정이지만 이제 새로운 제목 인 Async injection으로 이름이 변경되었습니다 .
연설에 동봉 할 일련의 블로그 게시물도 게시 할 계획입니다. 이 기사는 이미 작성되어 기사 큐에 앉아 게시 대기 중이므로 계속 지켜봐 주시기 바랍니다.