티스토리 뷰

웹개발/Java

OCP 개방 폐쇄 원책

yaku 2010. 12. 30. 13:33

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

Note

 열려 있어야 할 곳(확장)에는 열려 있어야 하고, 닫혀 있어야 할 곳(변경)에는 닫혀 있어야 한다는 원칙.

 

  쉽게 말하자면 확장은 가능하되 변경은 하지 않는 구조로 구성되어야 한다는 원칙이다. 어떻게 만들든 이미 만들어진 코드를 수정하지 않고 상속 받아서 처리하면 OCP가 만족되지 않을까? 그것만으로는 원칙을 지켰다고 말하기는 어려울 것 같다.

 

  객체 지향 5원칙은 개인적인 견해로 개발을 위한 원칙이라기 보다는 설계를 위한 원칙이라 생각한다. 개발 진행 중에 클래스를 수정해야 할 상황이 생겨버렸고, 변경은 하지 않는게 원칙이라고 하니 확장해버리자( = 상속받아서 처리해 버리자). 라는 것은 의도에 맞지 않는 행동이라는 것이다. Log4j 1.3 중 RollingFileAppender라는 클래스 때문에 골머리를 썩힌 일이 있다. RollingFileAppender 클래스가 처리하는 메소드의 몸통을 본 일이 있거나, 이를 변경하려고 해본 사람이 있다면 왜 잘못된 생각인지 바로 알 수 있을 것 같다. 결론 부터 말하자면 이 클래스는 final 클래스로 변경 자체가 불가능하게 설정된 클래스 이고, 4개 이상의 복잡한 상속 관계를 가지며, 보는 이로 하여금 상위 클래스로 뜻 없는 여행을 떠나 보내게 하는 클래스이다. 1.3버전 이후에는 Rolling + File + Appender 라는 복합적인 이름을 가지는 모습을 완전히 버리고 하나의 클래스가 하나의 기능을 수행하는 형태로 변경되었다.

 

 이러한 관점에서 생각했을 때 개방폐쇄의 원칙에 대해 다른 해석이 필요할 것 같다.

 

"변화되는 부분은 확장에 맡기고, 불변하는 부분 만을 클라이언트에 제공한다."

 

  예를 들어 클라이언트 클래스에서 데이터를 저장 기능이 필요하며, 경우에 따라서 DB에 저장할 수도 있고, 파일에 저장할 수도 있다. 라는 요구사항을 받았다고 했을 때 Storage라는 하나의 클래스에 FileSave 메소드와 DataBaseSave() 메소드를 구현해서 제공했다고 해보자. 클라이언트에서 메일로 데이터를 전송하는 새로운 요구 사항이 발생한다면 OCP의 원칙에 따라 확장을 선택하겠는가? Storage 클래스에 MailSave() 메소드를 하나 더 구현하겠는가? 어느쪽이든 원하는 결과를 보여줄 수 있지만 둘 다 그다지 아름다운 모습은 아닐 것이다.

 

  클라이언트 클래스에게는 Save() 라는 단일한 멤버 메소드를 가진 추상화된 클래스를 제공하고, 이를 구현하는 세부 클래스(Concrete Class)가 개별 기능을 수행하도록 구성한다면 OCP의 원칙도 지킬 수 있고, 클라이언트 클래스의 추가적인 수정 사항도 발생하지 않게 된다. 확장에 열린 구조는 새로운 요구 사항에 대해서 확장이 용이한 형태로 구현되는 것이고, 그 확장이 수직적인(상속을 통한) 확장만을 말하는 것은 아니라고 생각해 볼 수 있을 것 같다.

Keypoint
  • 변화되는 부분은 확장에 맡기고, 불변하는 부분만을 클라이언트에 제공한다.

    • Open : 클래스 수직관계(is - a)에서는 열려 있어야 한다. 즉 기반 클래스에서 파생 클래스로 확장이 가능해야 한다.
    • Close : 클래스 수평관계(has-a)에서는 변형되지 않아야 한다.

ocp01.jpg 

<<2-1. OCP를 위반하는 사례>>

 

개방 폐쇄 구성 방법

 

  1. 클래스 사이에 존재하는 공통 속성을 추출하여 인터페이스 또는 추상 클래스로 디자인한다.
  2. 이렇게 디자인된 추상 클래스를 상속 받아 세부 표현을 구현한다.
  3. 클라이언트는 이 클래스를 이용할 때에는 중간계층 또는 완충장치를 두어 직접 사용하지 않도록 구현하는 것이 좋겠다.

 ocp02.jpg

<<2-2. 추상화를 통한 확장에 열린 구조>>

 

ocp03(1).jpg 

<<2-3. 어댑터 클래스를 통한 접근>>

 

 

OCP를 위반했을 때 생기는 문제점

 클래스간에 n:m과 같은 관계를 갖는 다대다 형식의 복잡한 구조를 얻게 될 가능성이 생긴다.

위 2-1. OCP를 위반한 사례의 그림과 같이 구성된 경우 Storage 클래스에서 저장 매체를 확장하려고 했을 때 발생할 문제점은 크게 3가지 정도로 볼수 있을 것 같다.

 첫째. 클래스 자체를 수정하므로써 해당 클래스를 이용하고 있던 클라이언트 측이 같이 변경되어야 한다.

 둘째. Storage 클래스의 확장으로 인해 클라이언트 클래스도 그 기능을 사용할 수 있도록 같이 확장되어야 한다.

 셋째. Storage 클래스의 확장으로 인한 변경이 다른 메소드에 영향을 끼칠 수 있다.

 


'웹개발 > Java' 카테고리의 다른 글

LSP 리스코프 치환의 원칙  (0) 2010.12.30
SRP 단일 책임의 원칙  (0) 2010.12.30
OCP 개방 폐쇄 원책  (0) 2010.12.30
ISP 인터페이스 분리의 원칙  (1) 2010.12.30
oAuth 의 시나리오  (1) 2010.12.17
시큐리티 핵심 개념  (0) 2010.12.17
댓글
댓글쓰기 폼