정말 다형성(서브타입)이 IF를 줄일수 있을까?

Project 2009.06.25 01:56

 얼마전 강규영님의 글 "OOP란 조건문(if)을 줄이는 것"을 보고
정말 서브타입 다형성(subtype polymorphism) 이 if,else를 줄일수 있는가 생각해보았다.


예를들면 아래와 같은 클래스가 있다고 생각을 해보자.
식사 {
        밥() {
                if (아침) {
                   return 빵과우유;
                } else if (점심) {
                   return 짜장면;
                } else if (저녁) {
                   return 삼겹살;
                }
        }
}
아침 점심 저녁을 비교하는 세개의 IF문이 존재한다.
이 클래스를 아래와 같이 Interface를 이용해 분리를 해보겠다.

// 인터페이스
interface Food {
        eat();
}


// 오전을 나타내는 클래스
class Morning implements Food {
        eat() {
           return 빵과우유;
        }
}

// 오후을 나타내는 클래스
class Afternoon implements Food {
        eat() {
          return 짜장면;
        }
}

// 저녁을 나타내는 클래스
class Evening implements Food {
        eat() {
          return 삼겹살;
        }
}

class Meal {

        Food s;.

        // 식사지정 메소드
        setFood(Food s) {
           this.s = s ;
        }

        // 밥먹기
        eat() {
           return s.eat();
        }
}



public MealMain {
        public static void main(String[] args) {

                Food morning = new Morning();
                Food afternoon = new Afternoon();
                Food evening = new Evening();
                        

                Meal ml = new Meal();

                // 아침                
                ml.setFood(morning);
                print(ml.eat());

                // 점심                
                ml.setFood(afternoon);
                print(ml.eat());

                // 저녁                
                ml.setFood(evening);
                print(ml.eat());


        }
}

간단한 소스코드라서 별로 어렵지 않을것이다 (내가 복잡한걸 못 짠다.-_-)
결과적으로 IF문이 없어져 버렸다.

그런데 정말 다형성으로인해 IF문이 줄었던것일까?

public MealMain {
        public static void main(String[] args) {

                Morning morning = new Morning();
                Afternoon afternoon = new Afternoon();
                Evening evening = new Evening();
                       
                // 아침               
                print(morning.eat());

                // 점심               
                print(afternoon.eat());

                // 저녁               
                print(evening.eat());


        }
}
이 코드또한 다형성을 이용하지 않고도 방금전 코드와 같은 동작을 한다.

다시한번 반문해보자. 정말 다형성이 IF문을 줄였는가?
소스코드의 의도적인 리팩토링으로 인해 나타난 결과는 아닐까?

다형성은 객체간의 결합도 및 의존성을 줄이고
의존성 역전은 그 결과 부수적으로
가능하게된것은 아닐까?


OOP는 IF문을 줄일수가 있다.
(사실 이건 언어적 관점에서 IF문을 줄일수 있는것이다. 결과적으로 비교하는 로직은 없앨 수가 없다.)
하지만 다형성으로 IF문을 줄일수 있다는것은 주객이 전도된 이야기가 아닐까생각한다.
즉 IF문을 줄이기위해(결합도를 낮추기위해) 생겨난 , 필요한 특성이 아닐까?

p.s 강규영님의 의존성역전과 순환참조는 재미있게 읽었습니다.
Trackbacks 1 : Comments 8
  1. alankang 2009.06.25 09:13 신고 Modify/Delete Reply

    잘 읽었습니다. 뉘앙스가 미묘하긴 하지만 전체적으로 제가 이야기하는 바와 일치한다고 생각합니다.

    1. "다형성은 객체간의 결합도 및 의존성을 줄이고 의존성 역전은 그 결과 부수적으로 가능하게된것은 아닐까?"라는 서술에 대해서는, 객체라는 말을 일반적인 "모듈"이라는 말로 대체해보면 이렇게 얘기할 수 있습니다. "모듈간 결합도를 낮추는 다양한 방법이 있는데 OOP에서는 다형성을 이용하는 방법이 추가되었다. 다형성을 이용하여 결합도가 낮아지는 부분에서 의존성 역전이 나타난다." 즉, 다형성과 의존성 역전의 관계는 다형성으로 인해 간간히 의존성 역전이 나타나기도 한다는 정도가 아니라 다형성이 일어나는 모든 곳에서 의존성 역전이 일어난다고 해야 맞습니다. 물론 억지로 꼬아서 이상한 용도로 다형성을 쓰는 경우는 예외이겠으나 이런 코드를 두고 "객체지향적"이라고 말하지는 않죠. 이는 마치 GOTO만 없다고 해서 구조적 프로그래밍이 아닌 것과 마찬가지입니다.

    마지막에 보여주신 예시에서도 의존성 역전은 일어나고 있는데 Morning,Afternoon,Evening과 Food 사이의 상속관계가 여전히 남아 있기 때문이죠. 물론 이를 활용하는 코드가 없어서 동적인 프로세스 상에서는(이를테면 object diagram) 나타나지 않지만 정적인 구조(이를테면 class diagram)에는 의존성 역전이 나타납니다. 올바르게 사용된 realization 혹은 generalization 화살표(위 예시의 경우 올바르게 사용되었죠)는 의존성 역전을 일으킵니다.

    2. "하지만 다형성으로 IF문을 줄일수 있다는것은 주객이 전도된 이야기가 아닐까생각한다. 즉 IF문을 줄이기위해(결합도를 낮추기위해) 생겨난, 필요한 특성이 아닐까?"라고 하셨는데, 바로 제가 원글에서 하려던 이야기입니다. 다시 GOTO 비유를 따져보면 명확하죠. "while이 있으니 신기하게도 goto가 필요 없더라"가 아니라 "while을 없애기 위해 goto가 도입된 것"입니다.

    3. "결과적으로 비교하는 로직은 없앨 수가 없다"라는 언급은 주제에서 벗어난 이야기라고 생각합니다. 포인터를 레퍼런스로 대체해도 기계어 수준에서의 주소지칭방식에는 별 변화가 없을 것이고, GOTO가 없어져도 jmp(jump)는 남는 것과 마찬가지로, IF가 없어져도 jpz(jump if zero)는 남는거죠.

    4. "(다형성은) 즉 IF문을 줄이기위해(결합도를 낮추기위해) 생겨난, 필요한 특성이 아닐까?"라고 하셨는데 바로 이게 제 포스트에서 주장하는 내용입니다.

    • 아시모프 2009.06.25 10:34 Modify/Delete

      먼저 답글 감사합니다.

      야심한 시간에 글을써서 그런지 논지가 이상하게 간듯하네요.

      정리하자면,

      1. if문을 줄일수 있는것은 OOP의 언어적 특성 및 리팩토링에 의해 이루어 질수 있는것이지 다형성과는 큰 관계가 없다. 다형성의 목적은 2에 있다.

      2. 의존관계를 낮추기위해 다형성이 도입되었다.
      (goto제거를 위해 while의 도입과 같은맥락)
      의존관계역전 및 순환참조 문제의 제거는 부수적인 효과이다.

      입니다.
      2에 대해서는 서로 의견을 같이 하고 있는듯하네요.

      덧글에 대해서는,
      1. 마지막 예제에서 FOOD의 상속관계를 제거해도 if문은 필요없어집니다.
      그리고 다형성이 의존성 역전을 의해서만 사용된다는 말씀으로 알겠습니다. 이 부분에 대해서는 조금 이견이 있습니다 다시 정리해서 글을 쓰도록 하지요.

  2. alankang 2009.06.25 11:49 신고 Modify/Delete Reply

    "if를 줄일 수 있는 것은 OOP의 언어적 특성 및 리팩토링에 있는 것"이라고 할 때 "OOP의 언어적 특성"이란 다름아닌 다형성입니다. OO 언어에서 if를 줄이기 위한 리팩토링을 할 때 이용하는 수단 역시 다형성(Replace Conditional with Polymorphism)이고요.

    마지막 예제에서 상속관계를 제거해도 if문이 필요없는 이유는 처음 예제(아침/점심/저녁 중 하나의 케이스만 실행)와 달리 동적 프로세스 자체에 분기(branch 혹은 selection)가 없어져버렸기 때문(아침/점심/저녁 케이스 모두 실행)인거죠.

    • 아시모프 2009.06.25 13:04 신고 Modify/Delete

      제가 아직 다형성에 대한 이해가 부족해서 그런듯한데
      혹시 시간이 되시면 실제 다형성을 이용해 IF문을 줄인 코드를 볼수 있을까요?

      제가 리팩토링한 방식이 Replace Conditional with Polymorphism 라고 생각하고있었는데 다른가보군요.

    • alankang 2009.06.25 14:51 신고 Modify/Delete

      다른 것 아니고 같은 것 맞습니다. 다만 위 예시는 refactoring이라고 할 수 없죠. 왜냐하면 원래 코드에는 있던 분기가 없어졌으니까요.

      제가 처음에 썼던 글에 대한 부연을 위해 글을 몇 개 더 써보도록 하겠습니다.

  3. 써니 2009.06.25 15:01 Modify/Delete Reply

    이번 논의는 정말 다양한 분들이 참여를 해주시고 계신데...
    저는 따라가지도 못하고 있네요~ T.T

    역신 저는 coder에 불과하다는 것을 느낄 수 있는 것이...
    아시모프님이 코드로 올려주시니까... 아~ 이게 그 얘기구나 하고 있다는 겁니다.

    어려서 탱자탱자 놀았더니 나이먹고, 공부할 게 많습니다. 한숨...

    • 아시모프 2009.06.25 22:34 신고 Modify/Delete

      아니예요. 저도 잘 모르는걸요 :;;
      저도 공부할게 산더미 입니다.

      경험은 적고 머리는 나쁘니 책이라도 많이
      읽어야지 하는데 바쁘면 그것도 힘들고 여러모로
      어렵네요.

  4. 김진셍 2010.02.22 19:41 Modify/Delete Reply

    안녕하세요? 저같은 쌩초보가 이런 곳에 댓글 남겨도 괜찮을지 모르겠지만;;
    아침점심저녁 코드 보고 다형성에 대한 이해가 너무 잘 되어서 그냥 글 남깁니다.ㅋ_ㅋ

Write a comment