1. 클래스의 분리
- 처음에는 메서드로 기능을 분리했음
- 그 뒤에는 상하위클래스로 기능을 분리했음
- 이번에는 기능을 아예 연관없는 클래스로 분리할 생각임
분리 방법
- simpleConnectionMaker라는 클래스를 만들어서 연결관련 설정
- simpleConnectionMaker에 메서드 makeNewConnection을 구현
- 그 뒤, UserDAO에서 simpleConnectionMaker의 인스턴스를 생성하고,
makeNewConnection 메서드를 통해 새로운 연결을 생성함
생기는 문제
- 이전에 구현한 NUserDAO나 DUserDAO같이 UserDAO 코드 수정없이 상속받은 클래스에서 필요한 기능만 구현해서 사용하는 게 불가능해짐
- 상속이라는 문제에서는 벗어났지만, 다시 UserDAO의 코드수정이 불가피
1차 해결방법
- 인터페이스의 도입
- ConnectionMaker라는 인터페이스를 생성
- makeConnection이라는 메서드 선언
- 인터페이스를 구현한 NConnectionMaker,DConnectionMaker생성
- 인터페이스에 선언된 기능을 사용하는 것으로, UserDAO의 코드를 크게 변경하지 않고, 생성자에서 변수에 인스턴스를 할당하는 것으로 사용가능
문제점 - 여전히 커넥션의 구체적인 이름이 포함됨
private ConnectionMaker connectionMaker();
public UserDAO(){
//여기서 구체적인 NConnectionMaker와 같이 클래스의 이름이 나오게 된다.
connectionMaker = new NConnectionMaker();
}
- 구체적인 클래스의 이름(NConnectionMaker)가 나오게 되면서, 코드수정은 여전히 필요하게 된다.
- 물론 add,get과 같이 메서드에서는 구체적인 클래스 명이 나오지 않음
- 생성자만 변경하면 되는 정도로 변경점이 적어짐
2차 해결방법
- 파라미터(생성자의 매개변수)를 통한 오브젝트 주입
- 위에서는 생성자의 파라미터에 아무것도 없음
- 매개변수를 통해 생성자의 변수에 오브젝트를 전달하는 방법
public UserDAO(ConnectionMaker connectionMaker){
// 아래와 같이 이 클래스의 변수에, 매개변수의 오브젝트를 전달할 수 있다.
this.connectionMaker = connectionMaker;
}
- 이렇게 되면 클래스에서 NConnectionMaker와 같이 구체적인 클래스의 이름이 사라진다.
- 이제 UserDAO를 사용할 때(Main함수) 새로운 NConnectionMaker 인스턴스를 만든 뒤, 그 인스턴스를 UserDAO의 생성자로 넘겨주면 된다.



메인에서 생성자 파라미터를 통한 오브젝트 주입

위와 같이 이제 파라미터가 없으면 오류를 띄우는 것을 볼 수 있다.
파라미터에 값을 넣어서 해결한다.

리팩토링 결과

위와같이 잘 작동하는 것을 볼 수 있다.
1.3.4 원칙과 패턴
SOLID원칙과 디자인패턴
- 이제까지 개선해온 코드를 SOLID 원칙과 디자인패턴을 통해 설명한다.
개방 폐쇄 원칙
- 클래스나 모듈은 확장에는 열려있어야하고, 변경에는 닫혀있어야 한다.
- DB연결 방법이라는 기능 확장에는 열려있음
- NConnectionMaker와 같이 새로운 클래스를 만들어서 적용시킬 수 있음
- 동시에 UserDAO의 코드는 건드릴 필요가 없음
- 즉, DB연결방법이 변해도, UserDAO의 코드는 변경하지 않아도 되는 것이 개방 폐쇄원칙을 잘 지킨 결과라고 할 수 있음.
높은 응집도와 낮은 결합도
높은 응집도
- 하나의 클래스에 하나의 관심사에만 집중되어있다는 뜻
- 기능 하나에 집중되어있기 때문에, 이 관심사에 변화가 있다면 새로운 클래스를 생성해야함
- 만약 기능이 여러개 들어가 있다면, 관심사에 변화가 있는 경우, 클래스의 어느 부분을 수정해야 하는지 찾아야 함
- 응집도가 높으면, 찾을 필요없이 그냥 첨부터 새로 만들면 됨
낮은 결합도
- 책임과 관심사가 다른 오브젝트 또는 모듈과는 낮은 결합도가 바람직함
- 낮은 결합도란, 코드의 변경이 일어날 때, 관계를 맺고있는 다른 오브젝트한테 변화를 요구하는 정도
전략 패턴
- 필요에 따라서 변경이 필요한 알고리즘을 인터페이스를 통해 외부로 분리
- connectionMaker를 인터페이스로 분리해서 DB연결방법을 분리했다.
- 인터페이스를 구현한 구체적인 클래스를 필요에 따라 바꿔서 사용
- NConnectionMaker를 사용했다가, DConnectionMaker를 사용했다가 할 수있음
- 클라이언트에서 컨텍스트가 사용할 전략을 생성자 등을 통해서 제공해주는게 일반적
- 클라이언트 : UserDaoTest(main함수있는곳)
- 컨텍스트 : UserDao(인터페이스의 메서드를 사용하는 곳)
- 전략 : ConnectionMaker를 구현한 클래스
(실제 DB와 연결하는 로직이 있는 곳)