[직관적인 클린 코드를 위해] IF - ELSE IF 문 줄이기



이번 블로그 글은 '[직관적인 클린 코드를 위해] IF - ELSE IF 문 줄이기' 입니다.


직장에서 코딩을 하고 집에 와서는 친구와 함께하는 개인적인 프로젝트를 진행하며 직관적이고 깔끔한 코드를 위해 많은 고민을 했었습니다.

정답은 아니지만 그 경험을 공유하고자 하는 글이니 편하게 봐주셨으면 좋겠습니다.


코딩을 하다 보면 깔끔하고 보기 좋게 짜겠다는 처음 생각과 다르게 지저분해지는 경우가 많습니다.

그 주요 요인 중 하나로 수많은 IF 문과 그에 이어지는 ELSE IF 문 을 많이 꼽으실 겁니다. (Switch - case 도..)

처음 생각과 다르게 여러가지 조건이 생기고 그 조건을 검사해서 분류해야 하는 경우 가장 쉽게 할 수 있는 방법이기에 더욱 그런 것 같습니다.

하지만 그 간편함과 다르게 점점 IF 문이 자라날수록 코드는 분간하기 어렵고 직관적인 코드와는 거리를 두게 됩니다.



public static void main(String[] args) {
String type = "?";

if("A".equals(type)) {

}
else if("B".equals(type)) {

}
else if("C".equals(type)) {

}
}



위 예시같은 경우 String 변수 type에 들어있는 값을 분류하고 그에 따라 다르게 실행하기 위해 IF문과 ELSE IF 문이 걸려있습니다.

지금은 검사할 조건이 3가지라서 보기 어렵지 않을 수 있지만 조건이 증가함에 따라 보기 어려워지게 됩니다.



public static void main(String[] args) {
String type = "?";

if("A".equals(type)) {
for(int i = 0; i < 10;i++) {
if() {

}
}
}
else if("B".equals(type)) {
for(int i = 0; i < 10;i++) {
if() {

}
}
}
else if("C".equals(type)) {
for(int i = 0; i < 10;i++) {
if() {

}
}
}
}



위 예시처럼 보기 어려운 코드가 될 수 있습니다.

이를 해결하기 위해선 여러가지 방법이 있을 겁니다.

그 중 저는 Map과 해당 부분을 다른 클래스로 분리를 하는 방법을 섞어썼습니다.


String 변수 type에 특정한 값이 들어오고 그 값을 분류하여 그에 따라 실행해야 하는 로직이 각각 있다고 가정하겠습니다.



public static void main(String[] args) {
Map<String, Object> typeMap = new HashMap<>();

typeMap.put("A", new A());
typeMap.put("B", new B());
typeMap.put("C", new C());

String type = "?";

typeMap.get(type).test();
}



  • 이 예시에서는 HashMap을 이용하였고 메인문 안에서 생성했지만 편의상 그렇게 한 것이니 본인의 상황과 코드에 맞춰 구현하면 됩니다.


"A" 조건을 분류하는 IF 문의 내부 로직은 클래스 A의 test 메서드에, 

"B" 조건을 분류하는 ELSE IF 문의 내부 로직은 클래스 B의 test 메서드에, 

"C" 조건을 분류하는 ELSE IF 문의 내부 로직은 클래스 C의 test 매서드에 넣었습니다.


그럼 testMap.get() 에 type을 넣음으로써 원하는 분류되어있는 로직을 가지고 있는 객체가 리턴될 것 입니다.

하지만 여러 객체를 담을 수 있도록 Map의 Value 부분을 Object로 선언하여 원하는 매서드를 호출하지 못하게 되었습니다.

마우스를 가져다 대면 'Cannot resolve method test()' 라는 메세지가 뜰 것 입니다.


이유는 Object 에는 test() 라는 매서드가 없는데 호출을 하려고하니 에러가 나는 것 입니다.

이를 해결하기 위해선 간단하게 interface를 추가하면 됩니다.



interface Alphabet {
public void test();
}



위와 같은 Alphabet 인터페이스를 추가하고 해당 인터페이스 내부에는 test() 라는 추상매서드를 추가하고 Map 의 value 자리에는 Object 대신 인터페이스 Alphabet 을 써줍니다.

그리고 해당 인터페이스를 각각 분류한 클래스에 implements 해주고 test() 메서드를 Overriding 해주면 끝입니다.



class A implements Alphabet{

@Override
public void test() {
System.out.println("Alphabet A!!");
}
}

class B implements Alphabet{

@Override
public void test() {
System.out.println("Alphabet B!!");
}
}

class C implements Alphabet{

@Override
public void test() {
System.out.println("Alphabet C!!");
}
}



이제 main 문의 typeMap.get(type).test(); 에 있던 빨간색은 사라졌을 겁니다.

그리고 돌려보면 type의 값에 따라서 출력을 하는 것을 볼 수 있습니다.



public static void main(String[] args) {
Map<String, Alphabet> typeMap = new HashMap<>();

typeMap.put("A", new A());
typeMap.put("B", new B());
typeMap.put("C", new C());

String type = "B";

typeMap.get(type).test();
}



제가 준비한 내용은 여기까지 입니다.

부족함이 많은 글임에도 끝까지 읽어주셔서 감사합니다.

다음에도 이와 같이 기본적인 내용이지만 괜찮다고 생각드는 것이 있으면 잘 정리해서 공유드리겠습니다.

감사합니다.



+ Recent posts