제작과 사용은 매우 다르다. 소프트웨어 시스템에서는 준비 과정과 런타임 로직을 분리해야 한다.
즉 시작 단계라는 관심사를 분리해야 한다. 아래의 코드는 시작 단계를 분리하지 않고 구현한 예시이다.
// 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보다 더 빠르며 다양한 기능을 지원한다.
관심사를 관점으로 분리하는 가장 강력한 도구