모델링과 구현간의 상호작용은 객체간의 연관(association)에서 특히 주의해야 한다.
모델에서 모든 연결된(traversable) 연관에 대해서 동일한 속성들을 가지는 소프트웨어 메커니즘이 있다.
고객과 판매 응대자 간의 연관을 나타내는 모델은 두가지에 대응된다. 하나는 개발자가 두개의 실제적인 사람들 간의 연관된 것이라고 생각하는 관계를 추상화하는 것이다. 다른 하나는 두개의 자바 객체 간의 객체 포인터나, 데이터베이스 검색에 대한 캡슐화, 혹은 어떤 대응되는 구현에 해당한다.
예를 들어, 일대다 연관은 인스턴스 변수의 collection으로 구현될 수 있다. 하지만 설계는 그처럼 직접적일 필요는 없다. collection이 없을 수 있다. 접근자 메소드는 적당한 레코드를 검색하기 위해서 데이터베이스를 쿼리해서 그 결과를 기반으로 객체들을 초기화할 수도 있다. 설계는 모델에서 연관과 일치하는 행위를 가지는 특정 연결(traversal) 메커니즘을 지정해야 한다.
실생활에서 수많은 다대다 연관이 있으며, 상당수는 자연적으로 양방향이다. 하지만 이러한 일반적인 연관들은 구현과 유지보수를 복잡하게 한다. 게다가, 관계에 대한 본질에 대해서 거의 전달하지 못한다.
연관을 다루기 쉽게 만드는 데에는 다음과 같이 최소한 세가지 방법이 있다.
1. 연결 방향성을 강요
2. 다수성(multiplicity)를 사실상 지우고, qualifier를 추가
3. 필요하지 않은 연관은 제거
가능한 한 관계를 제약하는 것이 중요하다. 양방향 연관은 양쪽의 객체가 모두에게만 이해가 될 수 있음을 의미한다. 어플리케이션 요구사항이 양방향으로 호출하지 않는다면 한방향성은 상호의존을 감소시키며 설계를 간소화시킨다. 도메인을 이해함으로써 자연적인 방향성의 편중을 알 수 있다.
미국은 수많은 다른 나라처럼 많은 대통령들이 있었다. 이는 양방향이며, 일대다 관계이다. 하지만 "조지 워싱턴은 어느 나라의 대통령이었는가?" 와 같이 대통령의 이름으로 시작하는 경우는 드물다. 실질적으로 나라에서 대통령으로 연결되는 한방향 연관 관계로 간소화할 수 있다. 이러한 정재는 실질적으로 도메인에 통찰력을 반영할 뿐만 아니라, 더 실용적으로 설계를 만든다. 연관의 한쪽 방향은 다른 것보다 훨씬 더 의미가 있고 중요하다는 이해를 포함한다. 덜 근본적인 "대통령" 개념과는 관계없는 "사람" 클래스를 사용한다.
종종 더 깊은 이해가 "자격이 부여된(qualified)" 관계를 이끌어낸다. 대통령에 대한 것을 좀 더 자세하게 살펴보면, 한 국가는(시민 전쟁을 제외한) 한 시점에 하나의 대통령만을 가짐을 깨닫게 된다. 이러한 자격(qualifier)은 일대일로 다수성을 감소시키며, 명시적으로 모델에 중요한 규칙을 포함시킨다. 1790년에 미국의 대통령은 누구인가? 조지 워싱턴.
다대다 연관의 방향성 있는 설계는 사실상 일대다의 구현(훨씬 쉬운 설계)으로 간소화시킨다.
도메인의 편향을 반영하는 방향으로 일관되게 연관을 제약하는 것은 그러한 연관을 더 이해하기 쉽고 구현하기 더 단순하게 만들 뿐만 아니라, 나머지 양방향 연관에 중요성을 부여한다. 관계의 양방향성이 도메인의 의미론적인(semantic) 특성인 경우, 어플리케이션 기능에 대해 필요한 경우, 양방향성을 유지하는 것은 그러한 의미를 전달한다.
물론, 궁극적인 단순함은 만일 바로 작업에 중요하지 않거나 모델 객체의 기본적인 의미가 아니라면 서로 연관을 제거하는 것이다.
위의 모델에서 Brokerage Account에 대한 자바 구현은 다음과 같다.
String accountNumber;
Customer customer;
Set investments;
// 생성자 등
public Customer getCustomer() {
return customer;
}
public Set getInestments() {
return investments;
}
}
String accountNumber;
String customerSocialSecurityNumber;
// 생성자 등
public Customer getCustomer() {
String sqlQuery = "SELECT * FROM CUSTOMER WHERE "
+ "SS_NUMBER='" + customerSocialSecurityNumber + "'";
return QueryService.findSingleCustomerFor(sqlQuery);
}
public Set getInvestments() {
String sqlQuery = "SELECT * FROM INVESTMENT WHERE "
+ "BROKERAGE_ACCOUNT = '" + accountNumber + "'";
return QueryService.findInvestmentsFor(sqlQuery);
}
}
Brokerage Account와 Investment 간의 연관을 다수성을 줄여서 자격을 부여함으로써 모델을 정제해보자. 이는 주식(stock)당 하나의 투자(investment)만이 존재함을 의미한다.
이러한 설계는 모든 비즈니스 상황에 대해서 참이지 않을 수도 있지만, 특정 규칙이 무엇이든지 간에 연관에 대한 제약사항이 발견될수록 이러한 제약사항들이 모델과 구현에 포함되어야 한다. 이는 모델을 더 간결하고 유지보수하기 더 쉬운 구현으로 만든다.
자바 구현은 다음과 같다.
String accountNumber;
Customer customer;
Map investments;
// 생성자 생략
public Customer getCustomer() {
return customer;
}
public Investment getInvestment(String stockSymbol) {
return (Investment)investments.get(stockSymbol);
}
}
String accountNumber;
String customerSocialSecurityNumber;
// 생성자 등
public Customer getCustomer() {
String sqlQuery = "SELECT * FROM CUSTOMER WHERE "
+ "SS_NUMBER='" + customerSocialSecurityNumber + "'";
return QueryService.findSingleCustomerFor(sqlQuery);
}
public Investment getInvestment(String stockSymbol) {
String sqlQuery = "SELECT * FROM INVESTMENT WHERE "
+ "BROKERAGE_ACCOUNT = '" + accountNumber + "' "
+ "AND STOCK_SYMBOL = '" + stockSymbol + "'";
return QueryService.findInvestmentsFor(sqlQuery);
}
}
'Homo Faber > Concepts' 카테고리의 다른 글
Domain Driven 과 Model Driven (1) | 2008.02.28 |
---|---|
Domain Driven Design(2) - Entity [Reference Object] (0) | 2008.02.26 |
Hibernate에서 Equals 와 HashCode (0) | 2008.02.21 |
객체지향 어플리케이션에서의 Persistence (0) | 2008.02.15 |
Persistence를 어떻게 번역해야하나? (0) | 2008.02.14 |