제작과 사용은 매우 다르다. 소프트웨어 시스템에서는 준비 과정과 런타임 로직을 분리해야 한다.
즉 시작 단계라는 관심사를 분리해야 한다. 아래의 코드는 시작 단계를 분리하지 않고 구현한 예시이다.
// lazy initialization / lazy evalutation
public Service getService() {
if (service == null)
service = new MyServiceImpl(...)
return service;
}
문제점들은 다음과 같다.
getService 가 MyServiceImpl과 생성자 인수에 명시적으로 의존 -> 런타임에서 MyServiceImpl을 사용하지 않아도 의존성 해결하지 않으면 실행 불가
테스트할 때 테스트 전용 객체를 할당해야 한다.
런타임 로직과 객체 생성 로직 섞임 -> 테스트할 때 모든 실행 경로를 테스트 해야 한다.
MyServiceImpl이 불필요하게 클래스 전체에 대한 맥락을 알고 있다.
이를 해결하기 위한 방법은 Main 분리
, 팩토리
가 있다.
생성과 관련된 코드는 모두 main 혹은 main이 호출하는 모듈로 옮기기
애플리케이션이 객체가 생성되는 시점을 결정
IoC 기법을 의존성 관리에 적용한 메커니즘인 DI 활용 -> 새로운 객체는 넘겨받은 객체에 대한 책임만 맡으므로 SRP 법칙 만족
// 호출하는 객체가 반환되는 객체의 유형 제어하지 않음
MyService myService = (MyService)(jndiContext.lookup("NameOfMyService"));
여기서도 lazy initialization 사용이 가능하다.
소프트웨어 시스템은 관심사를 적절히 분리해 관리한다면 점진적으로 발전할 수 있다. 여기 저기 흩어져 있던 관심사를 모듈화하고 캡슐화하는 방식으로 영속성을 얻을 수 있다. 여기서 횡단 관심사
라는 말이 나오게 된다.
자바에서 사용하는 관점 혹은 관점과 유사한 메커니즘은 자바 프록시
, 순수 자바 AOP 프레임워크
, AspectJ
관점이 있다.
단순한 상황에 적합.
public class BankImpl implements Bank {
private List<Account> accounts;
...
// getter, setter 가지고 있는 POJO
// 비즈니스 논리는 POJO로 구현
}
public class BankProxyHandler implements InvocationHandler {
private Bank bank;
...
// invoke 함수와 세부사항 코드
}
// 프록시에 핸들러를 넘겨 주어서 bank 메서드 구현
Bank bank = (Bank) Proxy.newProxyInstance(
Bank.class.getClassLoader(),
new Class[] {Bank.class},
new BankProxyHandler(new BankImpl()));
프록시를 사용하면
자바 프레임워크를 이용해서 보다 쉽게 프록시 구현이 가능하다.
비즈니스 논리는 POJO로 구현하고 이는 다른 도메인에 의존하지 않으므로 테스트 및 유지, 보수가 편하다.
스프링 설정 파일에서 bean을 설정하여 JDBC -> DAO -> 도메인 객체로 프록시 되도록 한다.
// 빈 설정 파일 적용
XmlBeanFactory bf = new XmlBeanFactory(new ClassPathResource("app.xml", getClass()));
// bank 도메인에 직접 접근하는 것 같지만 사실 JDBC에 접근
Bank bank = (Bank) bf.getBean("bank");
EJB3를 통해서 더 간편하게 표현 가능하다.
Spring AOP보다 더 빠르며 다양한 기능을 지원한다.
관심사를 관점으로 분리하는 가장 강력한 도구