아무거나

[Design Pattern] Visitor Pattern 본문

Java & Kotlin/Java

[Design Pattern] Visitor Pattern

전봉근 2020. 1. 1. 21:24
반응형

방문자 패턴(Visitor Pattern)

객체에서 처리분리해서 사용할 수 있다. 즉, 분리되어 있는 상태에서 사용할 수 있게 해주는 패턴

 

 

  • Client: Visitor와 Visitable를 사용
  • Visitor: Visitable을 방문하는 형태
  • Visitable: Visitor를 받아들이는 형태
  • ElementVisitor: Visitable이 가지고 있는 멤버변수같은 값들을 가지고 원하는 처리를 한다.
  • VisitableElement: Visitable을 받아들이는 형태만 구현하게 된다.

방문자 패턴 예시 - 1

  • 방문자 패턴 관련된 클래스를 구현하자.

인터페이스를 구현
[Visitor.java]

package com.bkjeon.visitor;

public interface Visitor {
    public void visit(Visitable visitable);
}

[Visitable.java]

package com.bkjeon.visitor;

public interface Visitable {
    public void accept(Visitor visitor);
}

방문 관련 클래스를 구현
[VisitorA.java]

package com.bkjeon.visitor;

public class VisitorA implements Visitor {

    private int ageSum;

    public VisitorA() {
        ageSum = 0;
    }

    @Override
    public void visit(Visitable visitable) {
        if (visitable instanceof VisitableA) {
            ageSum += ((VisitableA) visitable).getAge();
        } else {
            // ..
        }
    }

    public int getAgeSum() {
        return ageSum;
    }
}

[VisitableA.java]

package com.bkjeon.visitor;

public class VisitableA implements Visitable {

    private int age;

    public VisitableA(int age) {
        super();
        this.age = age;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

메인 클래스를 구현한다.
[Main.java]

package com.bkjeon.visitor;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        List<Visitable> visitables = new ArrayList<>();
        visitables.add(new VisitableA(1));
        visitables.add(new VisitableA(2));
        visitables.add(new VisitableA(3));
        visitables.add(new VisitableA(4));
        visitables.add(new VisitableA(5));

        // visitor가 visitable을 방문해서(=accept) 어떤 동작을 한다.
        // 즉, VisitorA 클래스에서 조건에 따라 ageSum을 해준다.
        // 결과적으로는 모든 나이가 더해진다.
        Visitor visitor = new VisitorA();
        for (Visitable visitable: visitables) {
            visitable.accept(visitor);
        }

        System.out.println(((VisitorA) visitor).getAgeSum());
    }

}

결과

15

위의 방법말고 아래와 같이 구현할 수 있다.

package com.bkjeon.visitor;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        List<Visitable> visitables = new ArrayList<>();
        visitables.add(new VisitableA(1));
        visitables.add(new VisitableA(2));
        visitables.add(new VisitableA(3));
        visitables.add(new VisitableA(4));
        visitables.add(new VisitableA(5));

        // visitor가 visitable을 방문해서(=accept) 어떤 동작을 한다.
        // 즉, VisitorA 클래스에서 조건에 따라 ageSum을 해준다.
        // 결과적으로는 모든 나이가 더해진다.
        /*
        Visitor visitor = new VisitorA();
        for (Visitable visitable: visitables) {
            visitable.accept(visitor);
        }
         */
        Visitor visitor = new VisitorA();
        int ageSum = 0;
        for (Visitable visitable: visitables) {
            ageSum += ((VisitableA) visitable).getAge();
        }

//        System.out.println(((VisitorA) visitor).getAgeSum());
        System.out.println(ageSum);
    }

}

위와 같이 구현할 경우 우리는 VisitableA의 모양을 알고 있어도. VisitableA의 class를 수정할 수 없다. 이러한 상황에서 VisitableA와 같은 객체를 넣어주면 되기 때문에 외부에서도 충분히 구현이 가능하다. 예를 들어 loop문에 100줄짜리가 들어갈수도 있으므로 유지보수가 어렵다. 하지만 패턴을 사용한다면 (=accept) 좀 더 코드가 읽기 쉬워진다.

솔직히 개인적으론 for문에서도 저렇게 어렵게 사용되는 이 패턴을 굳이 실무에서 이용할 경우가 있는지는 잘 모르겠다. 이 글을 작성하면서도 어느 케이스에서 사용할지 이해가 잘 안되며 대략 이러한 패턴이 있다만 알고 넘어가기로 하자.

 

 

참고: https://www.inflearn.com/course/%EC%9E%90%EB%B0%94-%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4/dashboard

반응형
Comments