본문 바로가기

기타/객체지향의 탄생(2013)

객체지향의 탄생- Chain of Responsibility

 

  1. 채인 오브 리스판시빌리티 패턴(Chain of Responsibility)

1. 세상의 모든 객체들의 상호작용은 뭔가 원하고 뭔가 주는 과정의 끊임없는 반복이다. 벌이 꽃에게 꿀을 원하면 꽃은 꿀을 주었다. 새가 나무에게 집을 원하면 나무는 집을 주었다. 세상에서 가장 아낌없이 주는 존재는 자연이다. 자연은 모든 생물이 원하는 모든 것을 주었다. 땅위의 동물은 공기가 필요하니 공기를 주고, 물고기들은 물이 필요하니 물을 주었다. 자연은 생물의 생존에 필요한 모든 것들을 주었다.

 

세상의 모든 생명중에서도 자연에 가장 빚을 지고 있는 생명은 사람이다. 식량을 기르는 땅을 주고, 문명의 작동에 필요한 에너지를 제공하고, 한 가족이 행복하게 쉴 수 있는 산과 바다를 제공해 준다. 자연은 인류의 어머니다. 그래서 인류는 어머니 속을 썩이고 있다.

 

사람간의 관계도 뭔가 원하고 뭔가 주는 과정의 끊임없는 반복이다. 아마 인간의 기본적인 욕구로부터 뭔가 원하고 뭔가 주는 서비스업이 탄생되었을 것이다. 사람이 식당에 가서 밥을 원하니 식당은 밥을 주었다. 사람의 성욕은 나라도 억제하지 못해 음지에서 매춘업이 발달하였다. 여기서부터 온갖 서비스업이 발달하여 지금은 스타크래프트 잘하길 원하는 외국인에게 스타크래프트를 강습해주는 서비스가 생겼을 정도로 사람의 요청을 파고드는 온갖 서비스업이 발달하게 되었다.

 

사람의 요청이 많아질수록 복잡하고 어려운 요청도 생겼다. 그러면 복잡하고 어려운 요청을 처리하는 과정도 발달한다. 사람의 요청도 그러하니 세상의 요소를 담은 객체세상도 똑같을 것이다. 아마도 채인 오브 리스판시빌리티 패턴은 클라이언트 요청을 처리하는 기법이 발전하는 과정에서 생긴 패턴일 것이었다.

 

2. 산골이는 내성적인 성격으로 여행 경험이 거의 없었다. 산골이는 이래서는 안되겠다는 생각으로 해외 배낭여행을 알아보았다. 근데 해외여행 절차는 여행 초보자 산골이에게 너무 복잡하고 어려웠다.

 

일단 여행 지식이 없는 상태에서 어느 여행지를 선택하는 것이 좋을지 판단이 서지 않았다. 여행지를 골랐으면 항공권을 찾아야 하는데 저렴하면서 최단경로의 항공권 찾기가 만만치 않았다. 항공권을 찾으면 예약해야 하는데 성수기라 항공권 구하기도 쉽지 않았다. 용케 예약을 했으면 여행지에 대해 새부적인 여행코스를 짜야 하는데 경험이 없는 상태에서 여행 코스 짜기가 보통 어려운것이 아니었다. 또한 해당 여행지가 비자 발급이 필요하다는 것을 늦게 알아서 자칫하면 비자발급도 제때 못할뻔 했다. 여행 준비물은 어떻게 해야되는지 혹시 빠진건 없는지 걱정이 되었고 출국 당일날에는 맥가이버칼은 소지하고 탑승할수 없다는 말을 듣고 아차 싶었다. 출국은 용케 했는데 입국시 영어를 못해 어린아이처럼 갈팡질팡 거리기도 했다. 현지에서의 여행은 고난의 시작이었다.

 

3. 산골이는 여행에 대한 개념이 부족하다보니 여행사의 존재를 잘 알지 못했다. 여행사는 여행자가 여행하기 편하게 모든 필요한 일들을 깔끔하게 정리하여 여행자에게 제공한다. 그럼 여행자는 여행의 새부 절차를 잘 모르더라도 여행사만 믿고 간편하게 여행 준비를 할 수 있다. 여행사가 여행사 본사, 항공사, 숙박업소, 현재 여행사와 관계를 맺고 여행에 관한 모든 서비스를 일괄 제공하기 때문이다.

 

산골이는 일단 어느 여행지를 선택하는 것이 좋을지 판단이 서지 않았는데 여행사와 상담후 적당한 여행지를 선택할수 있었다. 저렴한 항공권도 여행사가 한번에 찾아서 예약까지 도와주었다. 여권, 비자 발급등 여행에 필요한 모든 행정 절차도 알려주고 처리를 도와주었다. 여행지에 대한 코스 선택과 숙박지 선택도 여행사가 도와주었다. 현지에서 여행시 도움 받을 일이 있으면 결연을 맺은 현지 여행사의 도움을 받으면 되었다. 여행에 대한 지식도 없고 영어도 못하고 혼자 떠나서 모든게 낯설고 두려웠던 산골이는 그나마 여행사의 도움으로 편하게 여행을 할 수 있었다.

 

4. 산골이는 생전 처음 여행을 떠날때 준비과정부터 모진 고생을 겪었다. 모진 고생을 했던 이유는 산골이가 알아야 할 절차가 너무 많았기 때문이다.

 

[산골이가 여행을 가는데 초행길이라 뭘 준비해야 되고 어디가 좋을지 힘들어 한다.]

 

산골이같은 여행자를 위해서 여행사가 존재한다. 여행사는 항공사, 숙박업체, 현지 여행사등의 관련 서비스 업체와 관계를 맺고 여행자를 위한 맞춤 서비스를 제공한다.

 

[여행사는 산골이가 판단하기 어려운 것들을 알아서 해준다.]

 

[실습 코드 UML]

public abstract class TourCompany {

    private TourCompany next;

    protected String tourCompanyPerson;

    

    public final void support(Problem problem) {

        if(solve(problem)) {

            System.out.println(tourCompanyPerson+" 이(가)"+problem.getProblemName()+"을(를) 해결했습니다.");

        } else {

            if(next != null) {

                next.support(problem);

            } else {

                System.out.println(problem.getProblemName()+"은(는) 해결할 대상이 없다.");

            }

        }

    }

    

    public TourCompany setNext(TourCompany next) {

        this.next = next;

        return next;

    }

    

    protected abstract boolean solve(Problem problem);

} 

[여행회사 클래스를 만들고 공통적으로 할일을 선언한다.]

 

public class TourAdviser extends TourCompany {

    public TourAdviser() {

        this.tourCompanyPerson = "여행사 가이드";

    }

    

    @Override

    protected boolean solve(Problem problem) {

        boolean result = false;

        

        if(problem.getProblemName().contains("상담")) {

            result = true;

        } else if(problem.getProblemName().contains("행정")) {

            result = true;

        }

        

        return result;

    }

 

} 

[여행회사 클래스를 상속받는 상담사 클래스를 만든다. 이 클래스는 '상담'과 '행정' 관련한 문제를 해결한다.]

 

public class AirportAdviser extends TourCompany {

    public AirportAdviser() {

        this.tourCompanyPerson = "항공사 직원";

    }

 

    @Override

    protected boolean solve(Problem problem) {

        boolean result = false;

        

        if(problem.getProblemName().contains("항공권")) {

            result = true;

        }

        

        return result;

    }

 

} 

[여행회사 클래스를 상속받는 항공사 직원 클래스를 만든다. 이 클래스는 '항공권'과 관련한 문제를 해결한다.]

 

public class LocalGuide extends TourCompany {

    public LocalGuide() {

        this.tourCompanyPerson = "현지 여행 가이드";

    }

    

    @Override

    protected boolean solve(Problem problem) {

        boolean result = false;

        

        if(problem.getProblemName().contains("현지")) {

            result = true;

        }

        return result;

    }

 

}

[여행회사 클래스를 상속받는 현지 가이드 클래스를 만든다. 이 클래스는 여행가는 곳 '현지'와 관련한 문제를 해결한다.]

 

public class Problem {

    private String problemName;

    public Problem(String name) {

        this.problemName = name;

    }

    

    public String getProblemName() {

        return problemName;

    }

} 

[산골이의 걱정거리/문제를 담을 클래스를 만든다.]

 

public class Main {

 

    public static void main(String[] args) {

        List<Problem> problemList = new ArrayList();

        problemList.add(new Problem("여행지 상담"));

        problemList.add(new Problem("여행전 행정 처리"));

        problemList.add(new Problem("여권 발급"));

        problemList.add(new Problem("항공권 예약"));

        problemList.add(new Problem("현지 여행 정보"));

        problemList.add(new Problem("돈이 없네"));

        

        TourCompany adviser = new TourAdviser();

        TourCompany airAdviser = new AirportAdviser();

        TourCompany locGuide = new LocalGuide();

        

        // 아래 로직을 통해 체인으로 연결한다.

        adviser.setNext(airAdviser).setNext(locGuide);

        

        for(int i = 0 ; i < problemList.size() ; i++) {

            Problem p = problemList.get(i);

            adviser.support(p);

        }

    }

 

} 

[로직 클래스를 통해 실행한다.]

 

여행사 가이드이(가)여행지 상담을 해결했습니다.

여행사 가이드이(가)여행전 행정 처리을 해결했습니다.

여권 발급은(는) 해결할 대상이 없다.

항공사 직원이(가)항공권 예약을 해결했습니다.

현지 여행 가이드이(가)현지 여행 정보을 해결했습니다.

돈이 없네은(는) 해결할 대상이 없다.

[여권발급은 산골이가 직접 해야한다. 돈이 없을 경우 여행사는 서비스를 지원하지 않는다. 그 외의 경우는 여행사 관련 클래스들이 유기적으로 연결하여 해결한다.]

 

만약 산골이가 항공권 예약을 할때는 항공사와 연계해 적당한 항공권을 예약해주고, 여행 준비 과정은 전문 여행 상담원이 친절하게 안내해준다. 현지 숙박업체와도 결연을 맺고 저렴한 가격에 숙박 예약도 해준다. 현지 여행에서의 각종 일들은 여행사와 결연을 맺은 현지 여행사가 돕고 있다.

 

산골이는 오직 즐거운 여행 준비에만 집중하면 되고 나머지 복잡한 여행 절차는 여행사가 알아서 해준다. 산골이는 요청만 하면 되고 요청 처리 대상과 절차는 몰라도 된다. 체인 오브 리스판시빌리티 객체로 밀접하게 연결이 되어 있는 여행사 객체들이 알아서 처리해준다.

 

5. 나는 위키, 오픈소스를 좋아한다. 위키나 오픈소스는 압도적인 기술력과 자금력의 힘을 가진 어느 업체가 만든 것이 아니고 평범한 사람들이 자신이 제일 잘할수 있는 일에 조금씩 참여하는 경우가 뭉쳐서 인류에게 기여하는 훌륭한 결과를 탄생시켰기 때문이다. 나는 브리태니커나 윈도우 보다는 치밀한 관료조직이나 자금력 없이도 위대한 결과물을 탄생시킨 평범한 인류의 느슨하지만 강력한 연결고리에 큰 희망을 얻었다. 이것이 위키+이코노믹이 합친 신조어인 위키노믹스 정신이다.

 

채인 오브 리스판시빌리티 패턴은 내가 좋아하는 패턴이다. 왜냐면 작은 힘이 뭉쳐 큰 힘을 내는 협동정신을 보여주는 패턴이기 때문이다. 마치 한명의 천재보다 여러명의 평범한 사람들의 공동작업으로 더 위대한결과물을 창조하는 위키노믹스 정신과 같다. 그 객체들은 자신에게 주어진 작은 임무를 잘 수행하는 객체끼리 뭉쳐 좀더 큰 임무를 수행하는 객체 그룹으로 강력하게 변신한다.

 

이때 클라이언트는 오직 큰 임무를 수행하는 추상 객체만 인식하고 요청을 던지면 된다. 클라이언트는 요청을 처리하는 체인으로 묶인 객체들을 몰라도, 체인으로 묶인 객체들이 알아서 처리해준다. 체인으로 묶인 객체들이 알아서 주어진 임무를 처리할수있는 이유는, 자신이 처리하는 일과 처리못하는 일을 구분하고 처리못하는 일은 다른 객체가 처리하도록 요청을 위임하기 때문이다. 이때 체인에 연결된 객체의 순서를 미리 정해놓는데 프로그램 실행시에 실행 순서를 동적으로 바꿀수도 있다.

 

채인오브리스판시빌리티 패턴은 일반 관료 조직처럼 경직되지 않고 자유롭게 연결고리 순서를 조절할 수 있고, 클라이언트가 새부 객체를 모르고 요청을 던져도 일을 잘 처리한다. 마치 자유롭고 느슨하게 그러나 끈끈하게 연결되었고 수많은 무명인들의 참여로 위대한 결과물을 창조한 위키와 같다.

 

[Chain of Responsibility 패턴 원본]

 

 

덧 ) 이 객체지향의 탄생 원고는 제가 책으로 내려다가 일단 잘 안되었는데요. 이유는 비문이 많다. 단락내 주제가 중복된다. 어떤 상황 설명을 과장한다.등 입니다. 그래도 원고를 일단 블로그에 몽땅 풀어보고 언젠가 제대로 교정해서 다시 도전할 생각입니다. 이점을 감안해서 읽고 객체지향을 이해하는데 도움이 되셨으면 좋겠습니다. 의견도 주셨으면 좋겠습니다. 원고 조금만 교정하면 괜찮을것 같은 출판사 관계자분의 피드백도 환영합니다. 매주 월요일 발행 예정입니다.