공부용으로 작성되는 페이지입니다. 틀린 부분이나 환경에 따라 오류가 발생할 수 있습니다.
전편- 단일 책임 원칙 SRP
[C#] SOLID 원칙 : 단일 책임 원칙(SRP)
공부용으로 작성되는 페이지입니다. 틀린 부분이나 환경에 따라 오류가 발생할 수 있습니다. 객체 지향을 접하면서 몇 번이고 들어본 SOLID 원칙, 머리로는 알고 있는데 잘 익혔는지는 모르겠
hungrykang.tistory.com
1. 개방 폐쇄 원칙(OCP)의 개념
개방 폐쇄 원칙이란?
기존의 코드를 변경하지 않으면서 기능을 추가할 수 있어야한다는 원칙이다.
확장에 대해서는 open 되어있고, 수정에 대해서는 closed 되어있다는 의미이다.
즉, 객체를 직접적으로 수정하는 것을 제한해야한다는 원칙이다.
OCP = 추상화?

OCP는 결국 추상화를 권장하는 원칙이나 다름없다.
추상화를 통해 상속 받는 클래스에서 공톡적으로 구현해야 하는 클래스나 메소드를 만들 수 있다.
이런 특성을 통해 수정이 필요할때 직접적으로 객체를 수정하지 않고, 상속 관계에 맞춰 추가하는 방식으로 코드를 확장할 수 있다.
2.개방 폐쇄 원칙(OCP)의 사례
OCP가 지켜지지 않은 케이스
앞서 언급했듯이 OCP 원칙은 객체를 직접적으로 수정하는 것을 제한해야한다고 했다.
아래는 전화오는 대상에 따라 감정 상태가 바뀌는 내용이다.
#전화 타입에 따라 긴장도가 달라지는 예제
public enum UserTension
{
Idle,
annoyed,
comfortable,
tension
}
private UserTension _state = UserTension.Idle;
private String[] Calltype = ["friend", "family", "boss"];
public void Getcall(string type)
{
if(type == "friend")
{
switch(_state)
{
case UserTension.comfortable:
break;
}
}
if (type == "family")
{
switch (_state)
{
case UserTension.annoyed:
break;
}
}
if (type == "boss")
{
switch (_state)
{
case UserTension.tension:
break;
}
}
}
해당 코드는 ocp를 위반했다고 볼 수 있는데, 새로운 유형의 전화나 감정 상태가 추가될 때마다 Getcall 메서드의 코드가 변경되어야 하기 때문이다. if문과 switch문을 끊임없이 작성해야하게 된다는 것이다.
OCP 원칙을 지키기 위해서는 두 모듈이 만나는 지점에 추상클래스나 인터페이스를 정의하여 추상화를 해주고, 추상화에 의존하도록 코드를 작성해야한다.
class CallManager
{
#유저의 감정 상태를 정의하는 enum
public enum UserTension
{
Idle,
Annoyed,
Comfortable,
Tension
}
#걸려오는 전화 타입을 정의하는 enum
public enum CallType
{
Friend,
Family,
Boss
}
#초기 유저의 감정 상태
private UserTension _state = UserTension.Idle;
#전략 패턴을 위한 인터페이스
#각 전화 유형 클래스는 이 인터페이스를 상속받아 메서드를 구현
public interface ICallStrategy
{
void HandleCall(ref UserTension state);
}
#인터페이스 상속
public class FriendCall : ICallStrategy
{
public void HandleCall(ref UserTension state)
{
state = UserTension.Annoyed;
Console.WriteLine("친구에게서 전화가 왔습니다. 상태: Annoyed");
}
}
#인터페이스 상속
public class FamilyCall : ICallStrategy
{
public void HandleCall(ref UserTension state)
{
state = UserTension.Comfortable;
Console.WriteLine("가족에게서 전화가 왔습니다. 상태: Comfortable");
}
}
#인터페이스 상속
public class BossCall : ICallStrategy
{
public void HandleCall(ref UserTension state)
{
state = UserTension.Tension;
Console.WriteLine("상사에게서 전화가 왔습니다. 상태: Tension");
}
}
#전화 타입과 전략을 매칭하는 Dictionary
#!!새로운 전화 타입을 추가할 때 이 딕셔너리에만 등록하면 됨!!
private readonly Dictionary<CallType, ICallStrategy> _strategies;
#생성자에서 전략 객체들을 미리 Dictionary에 등록
public CallManager()
{
_strategies = new Dictionary<CallType, ICallStrategy>
{
{ CallType.Friend, new FriendCall() },
{ CallType.Family, new FamilyCall() },
{ CallType.Boss, new BossCall() }
};
}
#전화가 왔을 때 처리하는 메서드
#전략을 Dictionary에서 가져와 실행하며 상태를 변경
public void GetCall(CallType callType)
{
if (_strategies.ContainsKey(callType))
{
_strategies[callType].HandleCall(ref _state);
}
else
{
Console.WriteLine("알 수 없는 전화 유형");
}
}
#현재 상태를 출력하는 메서드
public void PrintState()
{
Console.WriteLine($"현재 상태: {_state}");
}
}
class User
{
static void Main()
{
var callManager = new CallManager();
callManager.GetCall(CallManager.CallType.Friend); // 친구 전화 -> Annoyed 출력
callManager.PrintState();
callManager.GetCall(CallManager.CallType.Family); // 가족 전화 -> Comfortable 출력
callManager.PrintState();
callManager.GetCall(CallManager.CallType.Boss); // 상사 전화 -> Tension 출력
callManager.PrintState();
}
}

Interface, Strategy,Dictionary를 사용하여서 기존의 코드를 수정하지 않고 확장할 수 있도록 만들었다.
여기서 새로운 전화 타입이 생긴다면, calltype enum에 새 type을 작성해준 다음 새 Strategy class를 만든 뒤 Dictionary에 추가해주기만 하면 된다. 즉, 추가 외의 작업은 이루어지지 않았다.
다만, 내가 생각했던 것보다 상당히 어려워서... 조금 더 간략하게 짤 수 있는 방법을 생각해봐야겠다.
참고자료
💠 완벽하게 이해하는 OCP (개방 폐쇄 원칙)
개방 폐쇄 원칙 - OCP (Open Closed Principle) 개방 폐쇄의 원칙(OCP)이란 기존의 코드를 변경하지 않으면서, 기능을 추가할 수 있도록 설계가 되어야 한다는 원칙을 말한다. 보통 OCP를 확장에 대해서는
inpa.tistory.com
'Unity > C#' 카테고리의 다른 글
[C#] Delegate : Action, Func (0) | 2025.03.16 |
---|---|
[C#] SOLID 원칙 : 단일 책임 원칙(SRP) (0) | 2025.03.06 |
[C#] Delegate(대리자) : Event, Lambda (0) | 2025.03.05 |