디자인 패턴에 대해 이야기하기 전에, 우선 패턴이 작동하는 방식에 영향을 주는 소프트웨어 디자인의 다섯 가지 핵심 원칙인 "SOLID 원칙"에 대해서 알아보도록 하겠습니다.
이번 포스팅에서는 개방 폐쇄 원칙에 대해 알아보겠습니다.
1. 단일 책임 (Single Responsibility) [링크]
2. 개방 : 폐쇄 (Open-Closed)
3. 리스코프 치환 (Liskov Substitution)
4. 인터페이스 분리 (Interface Segregation)
5. 종속성 역전 (Dependency Inversion)

#1. 개방 폐쇄 원칙
"Class가 확장에는 개방적이되 수정에는 폐쇄적이어야 한다."
SOLID 디자인에서 OCP(개방-폐쇄 원칙)는 Class 확장에는 개방적이되 수정에는 폐쇄적이어야 한다고 명시합니다. 원본 코드를 수정하지 않고도 새로운 동작을 생성할 수 있도록 Class를 구조화하는 것을 목표합니다.
대표적인 예시가 셰이프의 영역을 계산하는 Class입니다. 직사각형과 원 영역을 반환하는 메서드가 있는 AreaCalculator라는 클래스를 만들 수 있습니다.
#2. 필요한 상황 예시 & 코드
영역을 계산하기 위해 Rectangle Class에는 Width와 Height를 정의했으며, Circle Class에는 Radius와 파이 값만 필요한 상황이라고 가정하겠습니다.
public class AreaCalculator
{
public float GetRectangleArea(Rectangle rectangle)
{
return rectangle.width * rectangle.height;
}
public float GetCircleArea(Circle circle)
{
return circle.radius * circle.radius * Mathf.PI;
}
}
public class Rectangle
{
public float width;
public float height;
}
public class Circle
{
public float radius;
}
위의 코드도 충분히 기능을 수행하지만, AreaCalculator에 더 많은 도형를 추가하려면 각각의 새로운 도형을 위한 메서드를 생성해야 할 것입니다. 나중에 여기에 오각형이나 팔각형을 보내야 한다면 어떻게 할까요? 도형을 20개 더 추가해야 한다면 어떨까요?
- AreaCalculator Class는 지나치게 커져 통제 불능 상태에 빠질 것입니다.
Shape라는 기본 클래스를 만들고 도형을 처리할 메서드를 만들 수도 있습니다. 하지만 그렇게 하려면 각 도형의 형식을 처리하도록 로직 안에 여러 개의 if문이 있어야 합니다.
- 그런데 이러한 방식으로 구현하면 확장성이 떨어지지 않을까요?
원본 코드(AreaCalculator의 내부)를 수정하지 않고, 새로운 도형을 사용할 수 있도록 확장을 위한 프로그램을 여는 것이 좋습니다. 현재 AreaCalculator는 작동하지만, 개방-폐쇄 원칙을 위반합니다.

#3. 개선안 예시 & 코드
다음과 같이 Shape라는 추상 Class를 정의하겠습니다.
public abstract class Shape
{
public abstract float CalculateArea();
}
위 코드에는 CalculateArea라는 이름의 추상 메서드가 있습니다. 이제 Rectangle과 Circle이 Shape로부터 상속하도록 하면, 각 도형은 각자의 영역을 계산하고 다음과 같은 결과를 반환할 수 있게 됩니다.
public class Rectangle : Shape
{
public float width;
public float height;
// Tip: 추상 클래스를 상속받았을 경우, 존재하는 추상 메서드는 모두 override가 필요하다.
public override float CalculateArea()
{
return width * height;
}
}
public class Circle : Shape
{
public float radius;
// Tip: 추상 클래스를 상속받았을 경우, 존재하는 추상 메서드는 모두 override가 필요하다.
public override float CalculateArea()
{
return radius * radius * Mathf.PI;
}
}
위 Rectangle, Circle의 Class들은 이제부터 AreaCalculator Class에서 아래과 같이 단순화할 수 있게 됩니다.
public class AreaCalculator
{
// Tip: Rectangle, Circle Class 등 Shape를 상속받은 Class들을 모두 하나의 메서드로 처리 가능해진다.
public float GetArea(Shape shape)
{
return shape.CalculateArea();
}
}
수정된 AreaCalculator Class는 이제 추상 Shape Class에서 정의한 추상 메서드를 호출하는 방식으로 처리할 수 있게 되었습니다. 이제부터는 새로운 도형 Class를 정의해도 AreaCalculator Class의 소스 코드를 변경하지 않고 GetArea를 통해 CalculateArea 기능 로직을 수행할 수 있게 되었습니다.
- 즉, 원본 코드를 수정하지 않아도 기능을 확장할 수 있는 형태로 개선된 것이죠.

이제는 새로운 다각형이 필요할 때마다 Shape에서 상속하는 새 Class를 정의하면 됩니다. 각각의 서브 Class 도형들은 CalculateArea 메서드를 Override하여 반환할 수 있는 구조가 된 것이죠.
해당 구조를 사용하면 디버깅하기도 더 쉬워집니다. 새로운 도형에서 오류가 발생하더라도 AreaCalculator를 재검토할 필요가 없어지는 것이죠. (AreaCalculator 스크립트의 수정사항이 없기 때문입니다.)
- 즉, 이제부터는 기존 코드가 변경 없이 유지되므로 새로 작성한 코드에만 잘못된 로직이 있는지 검사하면 됩니다.
#4. 정리
C#뿐만 아니라 Unity에서 새로운 Class를 만들 때도 이러한 방식으로 Interface와 추상화를 활용해보는 것은 어떨까요? 이런 방식으로 구현하면 확장하기 까다로운 switch 또는 if문으로 도배하는 일이 적어질 것이라고 생각합니다. OCP(Open-Closed Principle): 개방 폐쇄 원칙에 맞춰 Class를 설정하는 데 익숙해지면 프로젝트의 규모가 커지게 되더라도 새로운 코드를 더 간편하고 유지보수 용이하기에 추가할 수 있을 것이라고 생각합니다.
해당 글은 Unity 공식 문서 - Level_up_your_code_with_Game_Programming_Pattern 내용과 저의 경험을 바탕으로 재해석한 글입니다.
틀린 내용이나, 다른 관점을 가지고 계시다면 댓글로 말씀 부탁드리겠습니다. :)
"댓글과 공감 버튼은 양질의 글을 작성하는데 큰 힘이 됩니다!"
감사합니다.
'디자인 패턴' 카테고리의 다른 글
| 3. [Design Pattern] 객체 지향 설계의 5가지 SOLID 원칙 - 라스코프 치환 원칙 (0) | 2024.10.30 |
|---|---|
| 1. [Design Pattern] 객체 지향 설계의 5가지 SOLID 원칙 - 단일 책임 원칙 (1) | 2024.10.28 |