• Home
  • About
    • sdalbsoo's development blog photo

      sdalbsoo's development blog

      TIL

    • Learn More
    • Email
    • Facebook
    • Github
  • Posts
    • All Posts
    • All Tags
  • Projects

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

02 Sep 2018

Reading time ~2 minutes

Goals

  • OOP의 설게 원칙 ‘SOLID’중 ‘O’를 이해한다.
  • OCP를 쓰는 방법을 알아본다.
  • python 예제를 통해 OCP를 이해한다.
  • OCP 설계에서 주의해야할 점을 알아본다.

OCP의 유래

OCP(Open-Closed Principle)은 Bertrand Meyer의 ‘Object Oriented Software Construction’(1988)이라는 책에서 유래된 단어이다. 그러다 1996년 Robert C. Martin이 “The Open-Closed Principle”에서 이 접근 방법에 관해 설명하면서 더 유명해졌다.

OCP의 의미

OCP를 한글로 해석해보면 개방-폐쇄의 원칙이다. 코드를 개방한다는 말과 폐쇄한다는 말의 의미는 무엇일까? 기존의 코드(클래스, 모듈, 함수 등등)는 변경하지 않으면서(closed) 기능을 추가할 수 있도록(open) 설계되어야 한다는 뜻이다. 개발 작업을 하는 도중 클래스에 수정할 상황이 생긴다. 그런 상황이 생겼을 때, 수정한 클래스를 이용하는 다른 클래스를 줄줄이 고쳐야 한다면 고쳐야 할 클래스가 많아진다. 이를 위해서 OCP는 코드의 구조를 올바르게 리팩토링하여 나중에 이와 같은 유형의 변경이 더 이상의 수정을 유발하지 않도록 한다.

OCP를 쓰는 방법

  1. 변하는 것과 변하지 않는 것을 정확하게 구분한다. 변하는 것은(open) 가능한 한 변하기 쉽게 변하지 않는 것은(closed) 변하는 것에 영향받지 않게 설계하는 것이다.
  2. 두 클래스가 만나는 지점에 인터페이스를 정의한다. (아래의 예제에서 @abstractmethod가 붙은 부분이다) 이때, 인터페이스는 변하는 것과 변하지 않는 모듈의 교차점으로 서로를 보호하는 보호막 같은 역할을 한다.

OCP를 지키지 않는 예

  • 가장 대표적인 예를 가지고 설명하겠다.
class Rectangle(object):
    def __init__(self, width, height):
        self.width = width
        self.height = height


class AreaCalculator(object):
    def __init__(self, shapes):
        self.shpaes = shapes

    def total_area(self):
        total = 0
        for shape in self.shapes:
            total += shape.width * shape.height
        return total


def main():
    shapes = [Rectangle(2, 3), Rectangle(2, 4)]
    calculator = AreaCalculator(shapes)
    print("전체 넓이: {}".format(calculator.total_area()))  # 전체 넓이: 14


if __name__ == "__main__":
    main()

만약 이 코드에서 사각형이 아닌 삼각형에 대한 넓이를 계산하는 클래스를 넣는다고 하면 어떤 일을 해야 하는지 생각해보자. 우선은 Triangle이라는 클래스를 만들어야 하며 AreaCalculator에 있는 total_area메소드를 사용할 수 없으므로 Triangle에 맞는 total_area메소드를 만들어야 한다. 닫혀 있지 않은 상태이므로 삼각형뿐만 아니라 다른 도형도 추가한다고 생각해보면 계속 클래스와 메소드를 추가해야 한다.

OCP를 잘 지킨 예

from abc import abstractmethod


class Shape(object):
    @abstractmethod
    def area(self):
        pass


class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height


class AreaCalculator(object):
    def __init__(self, shapes):
        self.shapes = shapes

    def total_area(self):
        total = 0
        for shape in self.shapes:
            total += shape.area
        return total


def main():
    shapes = [Rectangle(1, 6), Rectangle(2, 3)]
    calculator = AreaCalculator(shapes)

    print("전체 넓이: {}"format(calculator.total_area))  # 전체 넓이: 12

if __name__ == '__main__':
    main()

코드에서 다른 모양의 넓이(삼각형, 사다리꼴 등등)를 계산해주는 AreaCalculator의 기능을 확장한다고 한다면, 우리는 Shape의 클래스를 만들면 되고 다른 코드(AreaCalculator 의 total_area 메소드)는 수정할 필요가 없다. 즉, 기존 코드(AreaCalculator 클래스)에 대해서는 닫혀있고(closed) 새로운 Shape 클래스에 대해서는 열려있다(open).

OCP 주의해야할 점

  • 확장되는 것과 변경되지 않는 모듈을 분리하는 과정에서 크기 조절을 잘해야 한다. 크기 조절에 실패하면 관계가 더 복잡해져서 설계를 망치는 경우가 있기 때문이다.
  • 인터페이스는 가능하면 변경해서는 안 된다.
  • 인터페이스 설계에서 적당한 추상화1 레벨을 선택하는 것이 중요하다.



참고 사이트

  • 개방-폐쇄 원칙
  • Understanding SOLID Principles: Open Closed Principle
  • 객체지향 SW 설게의 원칙 - OCP

  1. 그래디 부치(Grady Booch)에 의하면 ‘추상화란 다른 모든 종류의 객체로부터 식별될 수 있는 객체의 본질적인 특징’이라고 정의하고 있다. ↩



studyinterviewOCP Share Tweet +1