Solid - OCP

ChoiDevv·2023년 1월 5일
0

Before

SRP, 단일 책임 원칙을 사용했던 코드를 가지고 새로운 상황이 추가되었다고 가정하겠다. 그에 대한 연장선이기에 SRP의 글을 먼저 보고 와야한다.

OCP - 개방 폐쇄 원칙

OCP는 개방 폐쇄 원칙으로 확장에 있어서는 언제든지 가능하도록 열려있으나 수정에 있어서는 기존 코드를 수정해서는 안된다는 원칙이다.

Code

망나니개발자님의 게시글을 참고하였습니다.

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의 규칙을 지켰다 할 수 있다.

profile
기억보단 기록을

0개의 댓글