본문 바로가기

Design Pattern/구조(Structural) 패턴

11. 방문자 패턴 Visitor Pattern

목차

1. Visitor Pattern 이란?

2. Visitor Pattern 클래스 다이어그램 예시

3. 코드 예시

4. 실행 결과


Visitor Pattern 이란?

 

데이터 구조와 데이터 처리를 분리해주는 패턴 입니다.

 

데이터 처리 방식을 기존의 소스 코드 변경 없이 새로운 클래스 추가만으로 확장할 수 있으므로 

개방-폐쇠 원칙을 준수할 수 있습니다.

 

데이터 구조는 Composite Pattern 을 사용해 표현을 사용합니다.


Visitor Pattern 클래스 다이어그램 예시

 

이름 내용
Unit 데이터 구조를 나타내는 클래스
Item 단일 데이터 하나의정수 값을 가진 클래스
ItemList Unit 타입의 객체를 여러개 가질수 있도록 하여 단일데이터나집합데이터를 포함할 수 있도록 하는 클래스
Visitor 데이터 처리를 담당하는 클래스
SumVisitor 데이터가 가지고 있는 정수 값을 합하는 기능을 가진 클래스
AvgVisitor 데이터가 가지고 있는 정수 값을 평균내는 기능을 가진 클래스

 

 

Unit 에서 accept 메서드로 Visitor 객체의  방문을 허락해 줍니다.

Visitor 에서는 visit 메서드로 허락된 데이터를 처리합니다.


코드 예시

 

Unit 인터페이스

 

Visitor 의 방문을 허락해줄 accept 메서드를 정의합니다.

 

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

 

 

Item 클래스

Unit 을 구현합니다.

accept 메서드를 통해 visitor 의 방문(visit)을 허락해 줍니다.

 

public class Item implements Unit {
    private int value;

    public Item(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

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

 

ItemList 클래스

accept 메서드를 구현합니다.

배열에 담긴 Unit 들의 방문(visit)을 허용(accept)해줍니다.

 

public class ItemList implements Unit {
    private ArrayList<Unit> list = new ArrayList<>();

    public void add(Unit unit) {
        list.add(unit);
    }

    @Override
    public void accept(Visitor visitor) {
        Iterator<Unit> iter = list.iterator();

        while(iter.hasNext()) {
            Unit unit = iter.next();
            visitor.visit(unit);
        }

    }
}

 

 

Visitory 인터페이스

Unit 을 방문할 visit 메서드를 정의합니다.

 

public interface Visitor {
    void visit(Unit unit);
}

 

 

SumVisitor 클래스

visit 메서드를 구현합니다.

Item 클래스일 경우 값을 가져와서 더해주고, 아닐 경우 accept 를 하여 visit 를 허용합니다.

 

public class SumVisitor implements Visitor {
    private int sum = 0;

    public int getValue() {
        return sum;
    }

    @Override
    public void visit(Unit unit) {
        if(unit instanceof Item) {
            sum += ((Item)unit).getValue();
        } else {
            unit.accept(this);
        }
    }
}

 

 

AvgVisitor 클래스

마찬가지로 visit 메서드를 구현합니다.

 

public class AvgVisitor implements Visitor {

    private int sum = 0;
    private int count = 0;
    public double getValue() {
        return sum / count;
    }

    @Override
    public void visit(Unit unit) {
        if(unit instanceof Item) {
            sum += ((Item)unit).getValue();
            count++;
        } else {
            unit.accept(this);
        }
    }
}

 

 


실행 결과

 

Main 클래스

 

ItemList1, ItemList2, ItemList3 을 만들어 각각 원하는 만큼 정수값을 가진 Item 을 담습니다.

 

이후 가장 상위 배열인 ItemList1 을 accept 해주어 Visitor의 방문을 허락해 줍니다.

이때 SumVisitor 나 AvgVisitor 를 전달하여 어떤 방식으로 동작할지 선택합니다.

 

SumVIsitor 를 전달해 주었다면 모든 데이터가 합으로 나올 것이고,

AvgVisitor 를 전달해 주었다면 평균으로 나올것입니다.

 

public class Main {
    public static void main(String[] args) {

        ItemList list1 = new ItemList();
        list1.add(new Item(10));
        list1.add(new Item(15));
        list1.add(new Item(20));

        ItemList list2 = new ItemList();
        list2.add(new Item(25));
        list2.add(new Item(30));
        list1.add(list2);

        ItemList list3 = new ItemList();
        list3.add(new Item(35));
        list2.add(list3);

        SumVisitor sum = new SumVisitor();
        list1.accept(sum);
        System.out.println("합계: " + sum.getValue());

        AvgVisitor avg = new AvgVisitor();
        list1.accept(avg);
        System.out.println("평균: " + avg.getValue());

    }
}

실행 결과

합계: 135
평균: 22.0

 

 


참조

https://www.youtube.com/watch?v=QC8Q5MWB-mQ