SRP, 단일 책임 원칙을 사용했던 코드를 가지고 새로운 상황이 추가되었다고 가정하겠다. 그에 대한 연장선이기에 SRP의 글을 먼저 보고 와야한다.
OCP는 개방 폐쇄 원칙으로 확장에 있어서는 언제든지 가능하도록 열려있으나 수정에 있어서는 기존 코드를 수정해서는 안된다는 원칙이다.
망나니개발자님의 게시글을 참고하였습니다.
public class Service {
private static PasswordEncoder passwordEncoder;
public static void addUser(UserRequest request) {
StringBuilder sb = new StringBuilder();
/*
* StringBuilder encodedPassword = sb.append("{Encode}" + request.getPassword());
* */
StringBuilder encodedPassword = passwordEncoder.passwordEncode(request.getPassword());
User user = new User(request.getUserId(), encodedPassword);
// 세이브하는 DAO의 역할은 생략.
}
}
코드가 일정 부분 수정되었다. {Encode} 라는 문자열을 붙이는 방식으로 암호화를 하는데 {BCrypt} 라는 문자열을 붙이는 방식의 BCrypt 암호화를 적용하기로 정책이 바뀌었다. 따라서 새로운 클래스를 생성해서 만든다. 가상의 예이기 때문에 실제로 BCrypt가 적용되지는 않고 임의로 내가 작성했으니 이 점은 유의바란다.
public class Service {
private static PasswordEncoder passwordEncoder;
private static BCryptPasswordEncoder bCryptPasswordEncoder;
public static void addUser(UserRequest request) {
StringBuilder sb = new StringBuilder();
/*
* StringBuilder encodedPassword = sb.append("{Encode}" + request.getPassword());
* */
StringBuilder encodedPassword = bCryptPasswordEncoder.passwordEncode(request.getPassword());
User user = new User(request.getUserId(), encodedPassword);
// 세이브하는 DAO의 역할은 생략.
}
}
그 결과 정책과 관련도 없는 서비스 단 코드가 변경이 되었다. 이런 경우를 개방 폐쇄 원칙인 OCP를 위배했다고 볼 수 있다. 이러한 문제를 해결하기 위해서는 추상화의 개념을 적용해야 한다. 코드를 한 번 수정해보자.
public interface PasswordEncode {
StringBuilder passwordEncode(String password);
}
passwordEncode 메소드의 껍데기만 있는 인터페이스를 하나 생성한다. 이제 이걸 BCryptPasswordEncoder에 상속시킨다.
public class BCryptPasswordEncoder implements PasswordEncode {
@Override
public StringBuilder passwordEncode(String password) {
StringBuilder sb = new StringBuilder();
return sb.append("{BCrypt}" + password);
}
}
다음과 같이 작성될 것이고 인터페이스에 특성 상 오버라이딩해서 자식 클래스에서 구현 부분을 작성한다.
public class Service {
private static PasswordEncode passwordEncoder;
public static void addUser(UserRequest request) {
StringBuilder sb = new StringBuilder();
/*
* StringBuilder encodedPassword = sb.append("{Encode}" + request.getPassword());
* */
StringBuilder encodedPassword = passwordEncoder.passwordEncode(request.getPassword());
User user = new User(request.getUserId(), encodedPassword);
// 세이브하는 DAO의 역할은 생략.
}
}
아까는 조금 티나게 변경했었는데 결과적으로는 인터페이스를 선언해서 BCryptPasswordEncoder로 오버라이딩한 내용이 실행되는 로직이 완성될 수 있었다. 서비스 단 메소드 코드 또한 변경이 없었기에 OCP의 규칙을 지켰다 할 수 있다.