访问者模式访问超级类,接口和取消体面

时间:2018-01-25 12:11:56

标签: java design-patterns software-design visitor

我正在制定标准visitor pattern的变体,其中包含以下三个要求:

  • 对于每个节点,应首先访问该节点的所有超类
  • 对于每个类,应首先访问所有已实现的接口
  • 每次访问类或接口都应该能够取消对子类/实现类的访问

我的问题是双重的。 1)这是一个已知的方法还是有一个类似的模式与不同的名称? 2)这种方法有任何明显的改进或问题吗?

我将在这里用一个抽象的例子详细说明我的方法。

所访问的类层次结构是Collection ConcreteItemsConcreteItem实现CrossCuttingConcern并扩展AbstractItem类。

class Collection implements Visitable {
  public final List<ConcreteItem> concreteItems;

  public Collection(ConcreteItem ...concreteItems) {
    this.concreteItems = asList(concreteItems);
  }

  public Decent accept(Visitor visitor) {
    return visitor.visit(this);
  }
}

class AbstractItem implements Visitable {
  public Decent accept(Visitor visitor) {
    return visitor.visit(this);
  }
}

interface CrossCuttingConcern {
  default Decent acceptCrossCuttingConcern(Visitor visitor) {
    return visitor.visit(this);
  }
}

class ConcreteItem extends AbstractItem implements CrossCuttingConcern {
  public Decent accept(Visitor visitor) {
    // This will visit the abstract super type, interface, and concrete class in turn.
    // If any of those returns Decent.STOP, then the remaining ones are not visited.
    return Decent.allUntilStop(
        () -> super.accept(visitor),
        () -> this.acceptCrossCuttingConcern(visitor),
        () -> visitor.visit(this)
    );
  }
}

现在修改VisitorVisitable实现以返回名为Decent的类型(是的,也许不是它的最佳名称)。如果visit方法希望访问者停止在类层次结构中向下移动,则返回STOP。即如果您只想访问AbstractItems,则会从Decent.STOP返回visit(AbstractItem)

interface Visitor {
  Decent visit(Collection collection);
  Decent visit(AbstractItem abstractItem);
  Decent visit(CrossCuttingConcern interfaceItem);
  Decent visit(ConcreteItem concreteItem);
}

interface Visitable {
  Decent accept(Visitor visitor);
}

enum Decent {
  STOP,
  CONTINUE;

  public static Decent allUntilStop(Supplier<Decent> ...fns) {
    for (Supplier<Decent> fn : fns) {
      if (fn.get() == STOP) {
        return STOP;
      }
    }
    return CONTINUE;
  }

  public static BinaryOperator<Decent> product() {
    return (a, b) -> a == CONTINUE && b == CONTINUE ? CONTINUE : STOP;
  }
}

现在默认的访问者适配器实现返回Decent.CONTINUE并打印下面示例中使用的调试信息。

class VisitorAdapter implements Visitor {

  @Override
  public Decent visit(Collection collection) {
    System.out.println("visiting Collection: " + collection);
    // iterate over all concrete items and return STOP if one of the visit(items) does so
    return collection.concreteItems.stream()
        .map(a -> a.accept(this))
        .reduce(Decent.product())
        .orElse(CONTINUE); // return CONTINUE if collection contains zero items
  }

  @Override
  public Decent visit(AbstractItem abstractItem) {
    System.out.println("visiting AbstractItem: " + abstractItem);
    return CONT;
  }

  @Override
  public Decent visit(CrossCuttingConcern interfaceItem) {
    System.out.println("visiting CrossCuttingConcern: " + interfaceItem);
    return CONT;
  }

  @Override
  public Decent visit(ConcreteItem concreteItem) {
    System.out.println("visiting ConcreteItem: " + concreteItem);
    return CONT;
  }
}

此示例演示了工作要求:

public static void main(String[] args) {
  Collection collection = new Collection(new ConcreteItem(), new ConcreteItem());

  System.out.println("Visit all");
  new VisitorAdapter().visit(collection);
  System.out.println("");

  System.out.println("Stop at AbstractItem")
  new VisitorAdapter() {
    public Decent visit(AbstractItem abstractItem) {
      super.visit(abstractItem);
      return STOP;
    }
  }.visit(collection);
  System.out.println("");

  System.out.println("Stop at CrossCuttingConcern");
  new VisitorAdapter() {
    public Decent visit(CrossCuttingConcern interfaceItem) {
      super.visit(interfaceItem);
      return STOP;
    }
  }.visit(collection);
  System.out.println("");
}

提供以下输出:

Visit all
visiting Collection: Collection@7f31245a
visiting AbstractItem: ConcreteItem@16b98e56
visiting CrossCuttingConcern: ConcreteItem@16b98e56
visiting ConcreteItem: ConcreteItem@16b98e56
visiting AbstractItem: ConcreteItem@7ef20235
visiting CrossCuttingConcern: ConcreteItem@7ef20235
visiting ConcreteItem: ConcreteItem@7ef20235

Stop at AbstractClass
visiting Collection: Collection@7f31245a
visiting AbstractItem: ConcreteItem@16b98e56
visiting AbstractItem: ConcreteItem@7ef20235

Stop at Interface
visiting Collection: Collection@7f31245a
visiting AbstractItem: ConcreteItem@16b98e56
visiting CrossCuttingConcern: ConcreteItem@16b98e56
visiting AbstractItem: ConcreteItem@7ef20235
visiting CrossCuttingConcern: ConcreteItem@7ef20235

因此;这看起来很熟悉,还是有更简单的方法来实现我的要求?

0 个答案:

没有答案