[SOLID] 개방 폐쇄 원칙(OCP)

SeungHyuk Shin·2021년 9월 12일
0

SOLID 원칙

목록 보기
2/5
post-thumbnail

개방 폐쇄 원칙의 정의


개방 폐쇄 원칙은 "확장에는 열려 있어야 하고, 변경에는 닫혀 있어야 한다."를 의미한다. 조금 더 쉽게 풀어 쓰자면, "기능을 변경하거나 확장할 수 있으면서 그 기능을 사용하는 코드는 수정하지 않는다."를 뜻한다.

한 가지 예시를 보자.

위 사진은 자바 어플리케이션에서 JDBC 매니저를 이용하기 위해 설계된 구조다. JDBC 매니저를 상속받는 PostgreSQL, Oracle, Sybase는 모두 변경에는 확장적이지만, 자바 어플리케이션은 수정에 폐쇄적인 것을 알 수 있다. 더 쉽게 이야기하자면, Oracle DB를 사용하다가 PostgreSQL을 사용하는 변화가 발생하여도 자바 어플리케이션에서 수정할 코드는 없다는 것이다. 즉, 개방 폐쇄 원칙은 하나의 변화가 다른 곳에도 연쇄적으로 변화를 일으키는 것을 방지하기 위해 만들어졌다.

그렇다면, 개방 폐쇄 원칙을 어떻게 지킬 수 있을까?

개방 폐쇄의 원칙을 지키는 법


개방 폐쇄 원칙의 핵심은 첫 번째로 변화하는 부분을 추상화하는 것이다. 위의 3가지 DB는 기능의 이름은 같더라도 구체적으로 어떻게 동작하는지는 다를 수 있다. 이 부분에 대해서 추상화함으로써 기능을 고정시킬 수 있습니다. 주로, 인터페이스를 통해서 구현을 한다.

메모리에서 byte를 읽어 오는 기능을 추가해야 할 경우, ByteSource 인터페이스를 상속받은 MemoryByteSource 클래스를 구현함으로써 기능 추가가 가능하다. 그리고 새로운 기능이 추가되었지만, 이 새로운 기능을 사용할 FlowController 클래스의 코드는 변경되지 않는다. 즉, 기능을 확장 하면서도 기능을 사용하는 기존 코드는 변경되지 않는 것이다.

위 그림과 같은 구조가 개방 폐쇄 원칙을 구현할 수 있는 이유는 확장되는 부분(즉, 변화되는 부분)을 추상화해서 표현했기 때문이다. 변화되는 부분은 byte 데이터를 읽어 오는 기능이었다. FlowController 클래스 입장에서 변화되는 부분을 ByteSource 인터페이스로 추상화함으로써 byte 읽기 기능을 고정시킬 수 있게 되었다.
따라서, byte 읽기 기능을 고정시켰기 때문에, 새로운 byte 읽기 기능 구현을 추가하면서도 FlowController 클래스를 수정하지 않아도 된 것이다.

두 번째는 상속을 이용하는 것이다. 예를 들어, 클라이언트의 요청이 왔을 때 데이터를 HTTP 응답 프로토콜에 맞춰 데이터를 전송해 주는 ResponseSender가 있다고 해보자.

ResponseSender 클래스의 send() 메소드는 헤더와 몸체 내용을 전송하기 위해 sendHeader() 메소드와 sendBody() 메소드를 차례대로 호출하며, 이 두 메소드는 알맞게 HTTP 응답 데이터를 생성한다. 이때, 이 두 메소드는 protected 공개 범위를 갖고 있기 때문에 하위 클래스에서 오버라이딩이 가능하다.

ZippedResponseSender 클래스는 기존 기능에 압축 기능을 추가해 주는데, 이 기능을 추가하기 위해 ResponseSender 클래스의 코드는 바뀌지 않았다. 즉, ResponseSender 클래스는 확장에는 열려 있으면서 변경에는 닫혀있는 것이다.

ResponseSender 클래스 예제는 템플릿 패턴을 사용한 것이다. 템플릿 메서드 패턴은 상위 클래스에서 실행할 기본 코드를 만들고 하위 클래스에서 필요에 따라 확장해 나가는 패턴이다.

개방 폐쇄 원칙은 유연함에 대한 것


개방 폐쇄 원칙은 변경의 유연함과 관련된 원칙이다. 만약 기존 기능을 확장하기 위해 기존 코드를 수정해 주어야 한다면, 새로운 기능을 추가하는 것이 점점 힘들어진다. 즉, 확장에는 닫히고 변경에는 열리는 반대 상황이 발생하는 것이다.

앞서 FlowController와 ByteSource 예에서 보듯이, 개방 폐쇄 원칙은 변화되는 부분을 추상화(ByteSource 인터페이스)함으로써 사용자(FlowController) 입장에서 변화를 고정시킨다. 이를 통해 사용자가 ByteSource의 확장에 폐쇄적일 수 있도록 만들어 준다.

상속을 이용한 개방 폐쇄 원칙 구현 예에서도 ResponseSender 클래스는 변화되는 부분을 sendHeader() 메서드와 sendBody() 메서드로 고정시켰다. 하위 클래스에서는 이 두 메서드를 오버라이딩 함으로써 기존 기능을 확장할 수 있었고, 반면에 이 두 기능을 하위 클래스에서 변경하더라도 ResponseSender 클래스는 변경할 필요가 없었다.

개방 폐쇄 원칙은 변화가 예상되는 것을 추상화해서 변경의 유연함을 얻도록 해준다. 따라서 코드에 대한 변화 요구가 발생하면, 변화와 관련된 구현을 추상화해서 개방 폐쇄 원칙에 맞게 수정할 수 있는지 확인하는 습관을 가져야 한다.

0개의 댓글