-
[디자인패턴] 개방-폐쇄 원칙 OCP, Open-Closed Principle개발지식 아카이브/Algorithms 2025. 2. 17. 07:00
Open-Closed Principle, OCP
저는 오늘 회사에서 OCP 원칙을 위반하는 코드를 찾아서 수정 제안을 드렸습니다. 그래서 오랜만에 SOLID 패턴 복습하면서, 디자인 패턴 포스팅을 작성합니다!
개방-폐쇄 원칙은 SOLID 원칙 중 하나로, "소프트웨어 개체(클래스, 모듈, 함수 등)는 확장에는 열려 있어야 하고, 변경(수정)에는 닫혀 있어야 한다"는 개념입니다.
즉, 기존 코드를 수정하지 않고 새로운 기능이나 동작을 추가할 수 있도록 설계해야 한다는 뜻입니다. 이 원칙을 잘 지키면 시스템을 확장할 때 기존에 안정적으로 동작하던 부분을 변경할 필요가 없어 유지보수가 쉬워집니다.
개방-폐쇄 원칙의 필요성
프로젝트가 커지면서 기능을 추가하거나 수정해야 할 일이 많아지면, 기존 코드에 직접 손을 대게 됩니다.
이렇게 되면 새로운 버그가 발생할 위험이 있고, 여러 모듈이 얽혀 있는 경우 [하나의 변경의 영향 범위]가 커지게 됩니다.
하지만 OCP를 따르면 새로운 기능은 기존 코드를 건드리지 않고 추가하는 방식으로 설계할 수 있으므로, 안정성과 확장성을 모두 확보할 수 있습니다.
OCP를 위반한 예시
아래는 OCP를 위반한 코드 예시입니다. 여기서는 도형(Shape)의 면적을 계산하는 기능을 구현하고 있는데, 새로운 도형이 추가될 때마다 calculate_area() 함수를 수정해야 합니다.
# OCP 위반 예시: 새로운 도형이 추가될 때마다 함수 수정 필요 class Rectangle: def __init__(self, width, height): self.width = width self.height = height class Circle: def __init__(self, radius): self.radius = radius def calculate_area(shape): if isinstance(shape, Rectangle): return shape.width * shape.height elif isinstance(shape, Circle): import math return math.pi * shape.radius ** 2 # 사용 예시 rect = Rectangle(3, 4) circle = Circle(5) print("Rectangle area:", calculate_area(rect)) print("Circle area:", calculate_area(circle))
위 코드에서는 새로운 도형 예를 들어 Triangle 클래스를 추가하려면 calculate_area() 함수에 조건문을 추가하는 등 기존 코드를 수정해야 하므로 OCP 원칙에 어긋납니다.
OCP를 준수한 예시
OCP를 준수하기 위해서는 추상화를 활용해 공통 인터페이스를 정의하고, 각 도형은 해당 인터페이스를 구현하도록 설계합니다.
이렇게 하면 새로운 도형을 추가할 때 기존의 계산 로직을 변경하지 않고, 새로운 클래스만 추가하면 됩니다.
from abc import ABC, abstractmethod import math # 공통 인터페이스(추상 클래스) 정의 class Shape(ABC): @abstractmethod def area(self): """도형의 면적을 계산하여 반환하는 메서드""" pass # Rectangle 클래스: Shape 인터페이스 구현 class Rectangle(Shape): def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height # Circle 클래스: Shape 인터페이스 구현 class Circle(Shape): def __init__(self, radius): self.radius = radius def area(self): return math.pi * self.radius ** 2 # 새로운 도형: Triangle 클래스 추가 (기존 코드를 수정할 필요 없이 확장) class Triangle(Shape): def __init__(self, base, height): self.base = base self.height = height def area(self): return 0.5 * self.base * self.height # 도형들의 총 면적을 계산하는 함수 def total_area(shapes): return sum(shape.area() for shape in shapes) # 사용 예시 shapes = [ Rectangle(3, 4), Circle(5), Triangle(6, 8) ] print("Total area:", total_area(shapes))
포인트 정리:
- 확장에는 열려 있음: 새로운 클래스 Triangle을 추가할 때 기존의 total_area() 함수나 다른 클래스의 코드를 전혀 수정하지 않고, 단지 새로운 클래스를 추가하여 기능을 확장할 수 있습니다.
- 변경에는 닫혀 있음: 기존에 작성한 Shape 인터페이스와 각 도형 클래스는 변경 없이 그대로 유지됩니다.
이처럼 OCP를 잘 적용하면, 새로운 요구 사항이나 기능 추가 시 기존 코드를 건드리지 않아도 되므로 안정성과 유지보수성이 크게 향상됩니다.
결론
개방-폐쇄 원칙은 소프트웨어 설계 시 유연성과 확장성을 확보하는 중요한 원칙입니다.
새로운 기능이 추가되더라도 기존의 안정적인 부분에 영향을 주지 않도록 클래스를 설계함으로써, 복잡한 시스템에서도 유지보수를 쉽게 할 수 있습니다.'개발지식 아카이브 > Algorithms' 카테고리의 다른 글
Python으로 계산기 구현하기 (Postfix) (0) 2019.12.05 [해커랭크 HackerRank] DP 알고리즘 Max Array Sum (0) 2019.11.03 [해커랭크 HackerRank] 배열 문제 Minimum Swaps 2 (0) 2019.10.30