값 객체에서 찾을 수 없는 엔티티의 주요 속성은 무엇인가?
- 엔티티는 헥사고날 아키텍처의 일급 객체(first-class citizen)다.
- 고유한 식별자를 갖는다.
값 객체는 변경할 수 있는가?
- 값 객체는 불변(Immutable)이다.
- 값 객체는 폐기할 수 있어야 하고 엔티티나 다른 객체 타입을 구성하는 데 사용할 수 있는 쉽게 교체 가능한 객체여야 한다.
모든 애그리거트는 제어하는 다른 객체와 통신하기 위해 반드시 진입점 객체를 가져야 한다. 이러한 진입점 객체의 이름은 무엇인가?
- 애그리거트 루트
- 애그리거트의 일부인 엔티티와 값 객체들에 대한 참조를 유지한다.
- 애그리거트 루트에서 해당 컨텍스트 하위의 모든 객체를 처리하는 책임을 위임한다.
- networkSwitch 엔티티는 이 라우터에 직접 연결된 스위치를 나타내고, 두 개의 메서드를 추가했다.
- addNetworkToSwitch()
- createNetwork()
public class Router {
private final RouterType routerType;
private final RouterId routerId;
private Switch networkSwitch;
public Router(RouterType routerType, RouterId routerId) {
this.routerType = routerType;
this.routerId = routerId;
}
public static Predicate<Router> filterRouterByType(RouterType routerType) {
return routerType.equals(RouterType.CORE) ? Router.isCore() : Router.isEdge();
}
public static Predicate<Router> isCore() {
return p -> p.getRouterType() == RouterType.CORE;
}
public static Predicate<Router> isEdge() {
return p -> p.getRouterType() == RouterType.EDGE;
}
public void addNetworkToSwitch(Network network) {
this.networkSwitch = networkSwitch.addNetwork(network);
}
public Network createNetwork(IP address, String name, int cidr) {
return new Network(address, name, cidr);
}
public List<Network> retrieveNetworks() {
return networkSwitch.getNetworks();
}
public RouterType getRouterType() {
return routerType;
}
}
도메인 서비스는 다른 헥사곤에 있는 객체들을 호출할 수 있는가?
- 도메인 서비스가
애플리케이션 핵사곤
이나 프레임워크 헥사곤
에서 동작하는 서비스나 다른 객체를 호출해서는 안된다.
- 반면
애플리케이션 핵사곤
이나 프레임워크 헥사곤
의 객체들은 도메인 서비스를 호출하는 클라이언트들이다.
public class NetworkOperation {
private final int MINIMUM_ALLOWED_CIDR = 8;
public void createNewNetwork(Router router, IP address, String name, int cidr) {
if (cidr < MINIMUM_ALLOWED_CIDR) {
throw new IllegalArgumentException("CIDR is below " + MINIMUM_ALLOWED_CIDR);
}
if (isNetworkdAvalilable(router, address)) {
throw new IllegalArgumentException("Address already exist);
}
Network network = router.createNetwork(address, name, cidr);
router.addNetworkToSwitch(netwokr);
}
private boolean isNetworkAvailable(Router router, IP address) {
var availability = true;
for (Network network : router.retrieveNetworks()) {
if (network.getAddress().equals(address) && network.getCidr() == cidr) {
availability = false;
break;
}
}
return availability;
}
}
- 새로운 네트워크 객체를 생성하고, 해당 객체를 라우터에 연결된 스위치에 추가하는 것을 담당한다.
- 네트워크 생성시 제약사항을 검사하는 등 엔티티와 값 객체에 잘 어울리지 않는 작업을 처리한다.
- 엔티티와 값 객체 클래스가 문제 영역을 따라 필요 이상으로 많은 기능을 가지고 너무 커지는 것을 방지하기 위해서다.
정책과 명세의 차이점은 무엇인가?
정책
- 정책(Policy)은 전략(Straegy)으로도 알려져 있으며, 코드 블록으로 문제 영역의 일부를 캡슐화하는 패턴이다.
- 정책의 특성은 제공된 데이터에 대해 어떤 작업이나 처리를 한다는 점이다.
- 정책은 커플링을 피하기 위해 의도적으로 엔티티와 값 객체를 분리해 유지한다.
명세
- 명세(Specification)는 객체의 특성을 보장하는 데 사용되는 조건(condition)이나 프레디케이트(predicate)와 같다.
- 명세의 특징은 단순한 논리적인 연산자보다는 더 표현적인 방법으로 프레디케이트를 캡슐화한다.
public interface Specification<T> {
boolean isSatisfiedBy(T t);
Specification<T> and(Specification<T> specification);
}
POJO로 비즈니스 규칙을 정의하면 어떤 장점이 있는가?
- POJO를 사용해 비즈니스 규칙을 모델링함으로써 POJO가 제공하는 재사용성과 단순성에 관련된 모든 이점을 활용할 수 있다.
- POJO는 다른 기술적인 세부사항으로부터 도메인 객체를 보호하는 중요한 목표와도 관련이 있다.
- 과도하지 않은 설계를 지원하는 데 필수적인 관심사의 분리에 기여할 것이다.