SOLID - 개방-폐쇄 원칙(Open-Closed Principle)

 

본 글은 자바 객체지향과 디자인패턴를 읽고 개인적으로 학습한 내용을 복습하기 위해 작성된 글로 내용상 오류가 있을 수 있습니다. 오류가 있다면 지적 부탁드리겠습니다.

1. 개방-폐쇄 원칙이란?

개방-폐쇠 원칙은 기존의 코드를 변경하지 않으면서 기능을 추가할 수 있도록 설계되어야 한다는 뜻이다. 이전에 살펴 본 학생 클래스에서 학생의 성적이나 출석기록을 출력하는 기능을 가지고 예를 들어보자.

성적표, 출석부 출력기능 사용

위의 그림에서 처럼 성적표와 출석부를 출력하는 기능을 클라이언트 클래스가 사용하도록 할 수 있다. 그러나 위의 방식은 OCP를 위반한다. 만약 새로운 기능인 도서 대여기록 출력을 추가하면 클라이언트 클래스를 다시 수정해야 하기 때문이다.

OCP를 위반하지 않는 설계를 할 때 가장 중요한 것은 무엇이 변하는 것인지, 무엇이 변하지 않는 것인지 구분해야한다는 점이다. 변해야하는 것은 쉽게 변할 수 있어야하고, 변하지 않아야 할 것은 변하는 것에 영향을 받지 않아야한다는 것이다.

그렇다면 어떻게 설계를 해야할까? 아래의 그림을 통해 OCP에 위배되지 않는 설계를 알아보자.

2. OCP를 만족하는 설계

OCP를 만족하는 설계

새로운 출력 매체를 표현하는 클래스를 추가하게 하고, 이러한 변경이 있더라도 기존의 클래스(클라이언트)가 영향을 받지 않게 클라이언트 클래스가 개별적인 클래스를 처리하지 않도록 하고, 인터페이스에서 구체적인 출력 매체를 캡슐화해 처리하도록 한다.

OCP를 보는 또 하나의 관점은 클래스를 변경하지 않고도 대상 클래스의 환경을 변경할 수 있는 설계가 되어야 한다는 것이다. 이것은 특히 단위 테스트를 수행할 때 매우 중요하다.

예를 들어 테스트 대상이 되는 기능이 네트워크를 통해 웹 서비스를 사용한다고 가정해보자. 이런 경우 데이터베이스나 웹서버를 설치해야만 테스트를 진행할 수 있다. 하지만 단위 테스트의 가장 중요한 점은 빠른 시간에 자주 테스트를 해야한다는 것인데 시간이 많이 소요되는 데이터베이스나 웹서버 설치는 테스트를 회피하게 되는 요인이 된다. 따라서 테스트 대상 기능이 사용하는 실제 외부의 서비스를 흉내내는 가짜 객체를 만들어 테스트의 효율성을 높일 필요성이 있다.

실제 서비스에서 사용할 객체를 그대로 테스트할 때 위험이 따르는 경우도 존재한다. 예를 들면 어떤 기능이 데이터베이스를 사용할 때 테스트를 위해 데이터베이스에 삭제를 포함한 여러 작업을 실행한다고 가정해보자. 이 경우 실제 데이터베이스에 변경이 생기게되는 위험이 발생한다. 따라서 테스트를 위해 실제 데이터베이스 기능을 데체하는 가짜 객체를 만들 필요가 있다.

또한 테스트 대상 기능이 특정 상태에 의존해서 동작할 수 있다는 점도 고려해야한다. 예를 들어 비행기 관제 기능 중 동시에 착륙하려는 비행기 수가 1,000대인 경우 테스트를 한다면 어떻게 해야할까? 실제 1,000대의 비행기를 착륙시킬 수는 없기 때문에 1,000대의 비행기를 대신할 모의 객체를 이용하는 것이 좋다.