-
if else if else if else, no more프로그래밍 2023. 11. 2. 23:15
중첩 if else문을 사용하지 마세요. 그럼 어떻게 코딩함???
프로그램 개발에서는 수 많은 if else 구문으로 작성되게 된다.
javascript에 callback 지옥이 있듯, 일반적인 모든 프로그래밍에는 if else 지옥이 있다.
흔히 비즈니스 코드에서 나타나는 if else 구문을 줄여 보자.
먼저 아래의 예제를 보자
public enum ENUM_STEP_TYPE { None, Ing, Complete, Cancel }
public class GetStepService { private readonly IGetStepNoneRepository _noneRepo; private readonly IGetStepIngRepository _ingRepo; private readonly IGetStepCompleteRepository _compeleteRepo; private readonly IGetStepCancelRepository _cancelRepo; public GetStepService(IGetStepNoneRepository noneRepo , IGetStepIngRepository ingRepo , IGetStepCompleteRepository completeRepo , IGetStepCancelRepository cancelRepo) { _noneRepo = noneRepo; _ingRepo = ingRepo; _completeRepo = completeRepo; _cancelRepo = cancelRepo; } public StepModel GetStepData(ENUM_STEP_TYPE type, string id) { StepModel result = null; if(type == ENUM_STEP_TYPE.None) { result = _noneRepo.GetStep(id); } else if(type == ENUM_STEP_TYPE.Ing) { result = _ingRepo.GetStep(id); } else if(type == ENUM_STEP_TYPE.Complete) { result = _completeRepo.GetStep(id); } else if(type == ENUM_STEP_TYPE.Cancel) { result = _cancelRepo.GetStep(id); } return result; } }
간단한 예제를 작성해 보았다.
먼저 위 예제는 아직 if else 지옥에 들어가지 않았다.
하지만, ENUM_STEP_TYPE이 추가될 경우 계속적으로 if else가 추가될 가능성이 높다. 또한 생성에 필요한 Repository도 늘어날 것이다.위 구문을 switch 패턴 매칭으로 처리할 수 있을 것이다.
그러나 필자가 제안하는 방식은 아래와 같다.
public interface IGetStepRepository { StepModel GetStep(string id); } public class GetStepNoneRepository : IGetStepRepository { public StepModel GetStep(string id) { //TODO : retrieve step data } } //TODO : implement else... public class GetStepRepositoryFactory { private readony Dictionary<ENUM_STEP_TYPE, IGetStepRepository> _states = new () { { ENUM_STEP_TYPE.None, () => new GetStepNoneRepository() }, { ENUM_STEP_TYPE.Ing, () => new GetStepIngRepository() } //write continue... } public static IGetStepRepository Create(ENUM_STEP_TYPE type) { return _states[type](); } } public class GetStepService { private readonly Dictionary<ENUM_STEP_TYPE, Func<string, StepModel>> _states; public GetStepService() { _states = new() { { ENUM_STEP_TYPE.None, (id) => GetStepRepositoryFactory.Create(ENUM_STEP_TYPE.None).GetStep(id); }, { ENUM_STEP_TYPE.Ing, (id) => GetStepRepositoryFactory.Create(ENUM_STEP_TYPE.Ing).GetStep(id); }, { ENUM_STEP_TYPE.Complete, (id) => GetStepRepositoryFactory.Create(ENUM_STEP_TYPE.Complete).GetStep(id); }, { ENUM_STEP_TYPE.Cancel, (id) => GetStepRepositoryFactory.Create(ENUM_STEP_TYPE.Cancel).GetStep(id); }, } } public StepModel GetStepData(ENUM_STEP_TYPE type, string id) { StepModel result = _states[type](id); return result; } }
위와 같이 변경할 수 있다. (의존성 주입에 따라서 다소 다른 코드가 발생할 수 있다.)
위와 같은 코드의 장점은 선언형 분기이다.
우리가 흔히 겪는 가독성이 떨어지는 코드는 수 많은 if else 분기에 더해 내부적으로 if else가 복잡하게 발생하는 코드 이다.
위와 같은 구조를 만들기 위해서는 기본적인 구조 설계를 필요로 한다.
또한 각 기능별로 선언형 분기를 선언하게 되므로 명확하게 되고, 강제적으로 구조를 만들 수 밖에 없다.
따라서, if else 지옥에서 빠져나오려면 내가 작성하고 있는 코드의 구성 요소 전체를 고려하면서 작성해야 하고, if else 구
문이 예상보다 많은 구성을 갖는 다면 적극적으로 위의 방법을 고민해 보아야 한다.
위와 같은 코드 작성을 통해 작성한 사람도, 그것을 분석하고 구성요소를 추가하거나 수정해야 하는 사람도 명확한 구성을 갖는 코드를 다루게 되므로 여러 부분에서 장점이 있다.
사실, 우리는 이러한 해결 방법을 Factory패턴을 통해서 해결하는 것을 알고 있을 것이다.
위와 같이 Dictionary를 활용해서 보다 부수적인 코드를 줄이고 명확한 선언형 조건 코드를 작성하도록 하자.
'프로그래밍' 카테고리의 다른 글
Movin'In 모바일이 포함된 임대 부동산 관리 플랫폼 (0) 2023.11.06 .Net HTTP 라이브러리 비교 (0) 2023.11.06 static method? static class? (0) 2023.11.02 두번 개발하지 않는 방법 (0) 2023.11.02 C# 병렬 실행 탐구 (1) 2023.11.02