[스프링] 관심사의 분리 ( 관계설정 책임의 분리 )
지난 포스팅까지
인터페이스를 이용한 확장을
알아 보았다.
그러나 한 가지 문제가 있었다.
UserDao 클래스의 관심사는 'DB 엑세스를 위한 SQL실행'이지 'ConnectionMaker 인터페이스의 구현객체와의 관계 설정'은 관심사가 아니다. UserDao 클래스가 한 가지 구현객체를 선택하면 두 클래스는 '종속'되어 버린다. 종속은 변화에 좋지 않은 관계이다.
"느슨한 결합"을 유지해야한다.
관계 설정 책임의 분리
클래스 사이의 '관계설정'이란, 한 클래스 안에 다른 클래스의 객체를 인터페이스 없이 생성하는 것을 의미한다. UserDao 클래스 생성자에서 AConnection 구현객체를 생성하였다. 여기에는 ConnectionMaker 인터페이스를 사용했지만 '통용적인' 의미에서 관계설정이라 표현하겠다.
public class UserDao {
private ConnectionMaker connectionMaker;
public UserDao( ) {
connectionMaker = new AConnectionMaker(); // 관계설정
}
public int add(User user) throws SQLException {
Connection c = connectionMaker.makeNewConnection();
// 생략....
}
public User get(String UserId) throws SQLException {
Connection c = connectionMaker.makeNewConnection();
// 생략....
}
}
관계설정의 책임 또한 관심사이므로 UserDao 클래스는 DB 엑세스를 위한 SQL실행의 관심사와 더불어 두 가지 관심사를 가지게 된다.
첫 번째 관심사 : DB 엑세스를 위한 SQL실행
두 번째 관심사 : Connection 인터페이스 구현객체와의 관계설정 책임
관심사가 여러가지이면 유지보수에 불리하다. 변화는 한 가지 관심사에서 발생한다. 그러나 한 가지 관심사를 여러 클래스가 공유하면 변화에 대응할 유지보수가 여러 클래스에서 발생하게 된다. 그러므로 관계설정의 책임을 외부로 돌려야 한다.
객체와 클라이언트 ( 생성자 와 setter 함수 )
A 객체와 B 객체가 있다. A객체가 B객체를 사용하면 A객체는 클라이언트 객체, B객체는 서비스 객체가 된다. 서비스 객체의 관계설정의 책임을 클라이언트 객체에게 넘기면 서비스 객체는 관계설정의 책임으로부터 자유로워진다.
UserDao 객체는 Main 객체가 사용한다. 그러므로 Main 객체는 클라이언트 객체, UserDao는 서비스 객체가 된다. 이때, Main객체에 관계설정 책임을 넘기는 것이다. 생성자나 Setter 함수로 관계설정을 해주어 UserDao의 관계설정을 클라이언트 객체인 Main 객체가 담당한다.
Main 클래스
public class Main {
// 관계설정 책임의 분리
public static void main(String[] args) throws SQLException {
User user = new User("22231123l","민구","1111");
// ConnectionMaker 구현객체 생성
ConnectionMaker connectionMaker = new AConnectionMaker();
// UserDao와 ConnectionMaker 간의 관계설정
UserDao userDao = new UserDao(connectionMaker); // 생성자 이용
//userDao.setConnetionMaker(connectionMaker); // setter 함수 이용
}
}
UserDao 클래스
public class UserDao {
private ConnectionMaker connectionMaker;
// 생성자
public UserDao(ConnectionMaker connectionMaker) {
this.connectionMaker = connectionMaker;
}
// setter 함수
public setConnectionMaker(ConnectionMaker connectionMaker){
this.connectionMaker = connectionMaker;
}
public int add(User user) throws SQLException {
Connection c = connectionMaker.makeNewConnection();
// 생략....
}
public User get(String UserId) throws SQLException {
Connection c = connectionMaker.makeNewConnection();
// 생략....
}
}
UserDao 클래스는 Main 클래스에서 관계가 설정된 구현 객체를 그대로 인터페이스 객체로 받으면 된다.
이로써, UserDao 클래스는 커넥션 객체 만들기 관심사로부터 완전히 '분리'되었다. ConnectionMaker의 구현객체가 변경되거나 코드가 수정되어도 UserDao 클래스의 코드를 수정할 필요가 없다. 이와같이, 한 가지 관심사의 변화가 한 가지 클래스의 코드 수정으로 대응 가능한 코드를 만들어야 유지보수가 용이해진다.
관심사를 '분리'하고 '확장'이 가능한 코드를 구성할 때,
'변화에 대응 가능한 코드'가 만들어진다.
참고문헌