노현진's Blog

Visitor Pattern

Visitor Pattern에 대해 설명하는 페이지입니다.

Posted
Preview Image
By HyunJinNo

Tags

Design Pattern, Java

1. Introduction

  • Purpose
    • Allowing one or more operations to be applied to a set of objects at runtime
    • Decoupling the operations from the object structure (= the set of objects)

      Info.

      It's important that the visitor pattern is used when the above two purposes are needed.

  • Use When
    • An object structure must have many unrelated operations performed upon it
    • The object structure can't change but operations on it can
    • Operations must be performed on the concrete classes of an object structure
    • Operations should be able to operate on multiple object structures that implement the same interface sets

2. Characteristics

  • Pros
    • Makes adding new operations easy
      • You can define a new operation simply by adding a new visitor
      • In contrast, if you spread functionality over many classes, then you must change each class to define a new operation
    • Gathers related opertations and separates unrelated operations
      • Related behavior is not spread over the classes defining the object structure; it’s localized in a visitor
      • Unrelated sets of behavior are partitioned in their own visitor classes
  • Cons
    • Adding new ConcreteElement classes is hard
      • The Visitor pattern makes it hard to add new subclasses of Element
      • Each new ConcreteElement gives rise to a new abstract operation on Visitor and a corresponding implementation in every ConcreteVisitor class
    • Breaking encapsulation
      • Visitor’s approach assumes that the ConcreteElement interface is powerful enough to let visitors do their job
      • The pattern often forces you to provide public operations that access an element’s internal state, which may compromise its encapsulation
  • Visitors can visit objects that don't have a common parent class.

3. Participants

  • Visitor
    • declares a visit operation for each class of ConcreteElement in the object structure
  • ConcreteVisitor
    • implements each operation declared by Visitor
  • Element
    • defines an Accept operation that takes a visitor as an argument
  • ConcreteElement
    • implements an Accept operation that takes a visitor as an argument
  • ObjectStructure
    • can enumerate its elements
    • may provide a high-level interface to allow the visitor to visit its elements
    • may be a composite or a collection like a set or list

4. How to Use (Example)

  • Visitor

    java
    1public interface ICarElementVisitor {
    2    public void visit(Wheel wheel);
    3    public void visit(Engine engine);
    4    public void visit(Body body);
    5    public void visit(Car car);
    6}
  • ConcreteVisitor

    java
    1public class CarElementPrintVisitor implements ICarElementVisitor {
    2    public void visit(Wheel wheel) {
    3        System.out.println("Visiting " + wheel.getName() + " wheel");
    4    }
    5    public void visit(Engine wheel) {
    6        System.out.println("Visiting engine");
    7    }
    8    public void visit(Body body) {
    9        System.out.println("Visiting body");
    10    }
    11    public void visit(Car car) {
    12        System.out.println("Visiting car");
    13    }
    14}
    java
    1public class CarElementDoVisitor implements ICarElementVisitor {
    2    public void visit(Wheel wheel) {
    3        System.out.println("Kicking my " + wheel.getName() + " wheel");
    4    }
    5    public void visit(Engine wheel) {
    6        System.out.println("Starting my engine");
    7    }
    8    public void visit(Body body) {
    9        System.out.println("Moving my body");
    10    }
    11    public void visit(Car car) {
    12        System.out.println("Starting my car");
    13    }
    14}
  • Element

    java
    1public interface ICarElement {
    2    public void accept(ICarElementVisitor visitor);
    3}
  • ConcreteElement

    java
    1public class Wheel implements ICarElement {
    2    private String name;
    3
    4    public Wheel(String name) {
    5        this.name = name;
    6    }
    7
    8    public String getName() {
    9        return this.name;
    10    }
    11
    12    @Override
    13    public void accept(ICarElementVisitor visitor) {
    14        visitor.visit(this);
    15    }
    16}
    java
    1public class Engine implements ICarElement {
    2    @Override
    3    public void accept(ICarElementVisitor visitor) {
    4        visitor.visit(this);
    5    }
    6}
    java
    1public class Body implements ICarElement {
    2    @Override
    3    public void accept(ICarElementVisitor visitor) {
    4        visitor.visit(this);
    5    }
    6}
    java
    1public class Car implements ICarElement {
    2    private ICarElement[] elements;
    3    public Car() {
    4        this.elements = new ICarElement[] {
    5            new Wheel("front left"), new Wheel("front right"),
    6            new Wheel("back left") , new Wheel("back right"),
    7            new Body(), new Engine() };
    8    }
    9    public void accept(ICarElementVisitor visitor) {
    10        for(ICarElement elem : elements)
    11            elem.accept(visitor);
    12        visitor.visit(this);
    13    }
    14}

© HyunJinNo. Some rights reserved.