我正在制定标准visitor pattern的变体,其中包含以下三个要求:
我的问题是双重的。 1)这是一个已知的方法还是有一个类似的模式与不同的名称? 2)这种方法有任何明显的改进或问题吗?
我将在这里用一个抽象的例子详细说明我的方法。
所访问的类层次结构是Collection
ConcreteItems
。 ConcreteItem
实现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)
);
}
}
现在修改Visitor
和Visitable
实现以返回名为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
因此;这看起来很熟悉,还是有更简单的方法来实现我的要求?