Backend
home
📘

[개념 정리] OCP-개방 폐쇄 원칙

생성 일시
2025/02/27 07:54
태그
Java
게시일
2025/02/28
최종 편집 일시
2025/03/01 14:34
GitHub 링크

1. 개방 폐쇄 원칙이란

소프트웨어 컴포넌트는 확장에 열려 있어야 하고 수정에 관해서는 닫혀 있어야 한다는 의미를 말한다.
다른 개발자가 작업을 수행하기 위해서는 반드시 수정해야 하는 제약 사항을 클래스에 포함해서는 안 된다는 사실을 의미한다.
다양하고 직관적이며 유해하지 않은 방식으로 소프트웨어 확장성을 유지하는 원칙이다.

2. 예시

개방-폐쇄 원칙을 따르지 않는 경우

Shape
package challenge.bad; public interface Shape {}
Java
복사
Rectangle
package challenge.bad; public class Rectangle implements Shape { private final int width; private final int weight; public Rectangle(int width, int weight) { this.width = width; this.weight = weight; } public int getWidth() { return width; } public int getWeight() { return weight; } }
Java
복사
Circle
package challenge.bad; public class Circle implements Shape { private final int radius; public Circle(int radius) { this.radius = radius; } public int getRadius() { return radius; } }
Java
복사
이 코드에서 클래스의 생성자를 활용하여 서로 다른 크기의 직사각형과 원을 쉽게 만들 수 있다. 여러 가지 도형을 만들었다면 모든 면적을 합할 차례이다. 면적의 합을 구하기 위해 AreaCalculator 클래스를 다음과 같이 정의한다.
AreaCalculator
package challenge.bad; import java.util.List; public class AreaCalculator { private final List<Shape> shapes; public AreaCalculator(List<Shape> shapes) { this.shapes = shapes; } /** * 도형을 추가하려면 이 클래스를 수정해야 한다. * 이 코드는 개방-폐쇄 원칙에 맞지 않는다. */ public double sum() { int sum = 0; for (Shape shape : shapes) { if (shape.getClass().equals(Circle.class)) { sum += (int) (Math.PI * Math.pow(((Circle) shape).getRadius(), 2)); } else if (shape.getClass().equals(Rectangle.class)) { sum += ((Rectangle) shape).getHeight() * ((Rectangle) shape).getWidth(); } } return sum; } }
Java
복사
각 도형은 면적을 구하기 위한 고유의 공식이 있으므로 도형의 유형을 구분하려면 if-else 또는 switch 구조가 필요하다. 또한 삼각형과 같은 새로운 도형을 추가하고 싶다면 새로운 if문을 추가하기 위해 AreaCalculator 클래스를 수정해야 한다. 이것은 이 코드가 개방-폐쇄 원칙을 위반한다는 것을 의미한다. 개방-폐쇄 원칙을 준수하도록 코드를 수정하려면 모든 클래스에서 몇 가지를 수정해야 한다.

개방-폐쇄 원칙을 따르는 경우

AreaCalculator에서 도형의 면적 계산 공식을 빼서 공식이 필요한 각 Shape 클래스로 옮기는 것이다. 즉 직사각형, 원 등의 각 도형에 해당하는 클래스에서 자신의 면적을 계산하도록 하는 것이다. 각 도형 클래스에서 면적을 계산하도록 Shape 인터페이스 정의에 area 메서드를 추가한다.
Shape
package challenge.good; public interface Shape { public double area(); }
Java
복사
Circle
package challenge.good; public class Circle implements Shape { private final int radius; public Circle(int radius) { this.radius = radius; } @Override public double area() { return Math.PI * Math.pow(radius, 2); } }
Java
복사
Rectangle
package challenge.good; public class Rectangle implements Shape { private final int width; private final int height; public Rectangle(int width, int height) { this.width = width; this.height = height; } @Override public double area() { return width * height; } }
Java
복사
AreaCalculator
package challenge.good; import java.util.List; public class AreaCalculator { private final List<Shape> shapes; public AreaCalculator(List<Shape> shapes) { this.shapes = shapes; } public double sum() { int sum = 0; for (Shape shape : shapes) { sum += (int) shape.area(); } return sum; } }
Java
복사
이 코드는 개방-폐쇄 원칙을 따른다. AreaCalculator 클래스를 수정하지 않고도 새로운 도형을 추가할 수 있기에 수정에 관해 닫혀 있으면서 확장에 관해서는 열려 있다.