이전 OCP, DIP의 문제점
이전 글의 OCP와 DIP는 생성자 주입을 통해 조금 더 세세한 분리를 통해 개선할 수 있다. 아래는 OCP와 DIP의 개선 코드이다.
OCP
예를 들어, 아래의 코드의 경우, OCP를 준수하기 위해선 변경에는 닫혀 있어야 한다. 하지만, 'SimpleCaculatorV1'에서 'SimpleCaculatorV2'로 변경할 때 '공학계산기' class 안에서 코드의 변경이 발생한다.
interface SimpleCaculator {
public void 더하기();
}
class SimpleCaculatorV1 implements SimpleCaculator{
public void 더하기(){}
}
class SimpleCaculatorV2 implements SimpleCaculator{
public void 더하기(){}
}
class 공학계산기 {
// SimpleCaculator simpleCaculator = new SimpleCaculatorV1();
SimpleCaculator simpleCaculator = new SimpleCaculatorV2();
public void 공학계산(){
simpleCaculator.더하기();
}
}
DIP
아래의 코드 역시, '공학계산기' class는 simpleCacculator 인터페이스와 SimpleCaclulatorV1 클래스를 의존하고 있다. 이부분 역시 DI를 통해 SimpleCaclulatorV1을 의존하지 않는 방향으로 개선이 가능할 수 있다.
interface SimpleCaculator {
public void 더하기();
}
interface 공학기능 {
public void 공학계산();
public void 공학더하기();
}
class SimpleCaculatorV1 implements SimpleCaculator{
public void 더하기(){}
}
class 공학계산기 implements 공학기능{
SimpleCaculator simpleCaculator = new SimpleCaculatorV1();
public void 공학계산(){}
public void 공학더하기(){}
}
OCP와 DIP 개선
아래와 코드와 같이 생성자 주입을 통해 OCP와 DIP를 개선할 수 있다.
Config 생성자
원하는 구현체를 반환해주는 Config 클래스를 작성한다. 이후, 기존 '공학계산기' 클래스는 Config를 통해 생성자 주입을 받아 인터페이스와 구현체를 매핑한다.
class config {
public SimpleCaculatorV1 SimpleCaculatorV1() {
return new SimpleCaculatorV1();
}
}
공학계산기 클래스
class 공학계산기 {
// SimpleCaculator simpleCaculator = new SimpleCaculatorV1();
private final SimpleCaculator simpleCaculator;
public 공학계산기(SimpleCaculator simpleCaculator) {
this.simpleCaculator = simpleCaculator;
}
public void 더하기(){}
public void 공학계산(){}
public void 공학더하기(){}
}
위처럼 구현체들을 관리해주는 별도의 클래스를 이용해 필요한 구현체들을 생성자 주입해줄 수 있다.
이렇게 별도로 별도로 관리할 경우, OCP와 DIP를 잘 지키도록 개선할 수 있다.
- OCP의 '변경에는 닫혀 있어야 한다' : 이후, SimpleCalculator의 구현체를 변경해야할 경우, Config를 수정해주면 된다. 따라서 공학계산기는 수정할 필요가 없으며, OCP를 잘 준수하고 있다.
- DIP의 '구현체가 아닌, 인터페이스에 의존해야한다' : 이제 공학계산기 내부에는 구현체가 없다. 따라서, 공학계산기는 구현체가 아닌 인터페이스에만 의존하고 있으므로, DIP를 잘 준수하고 있다.