为什么访问者负责访问者模式枚举的孩子吗?
-
22-08-2019 - |
题
根据我找到的代码,似乎观众需要知道的访问对象的结构和所需要的孩子们叫。这似乎有点在某些情况下,笨重的地方游客会想继续工作,即使当访问类被修改。
我想真正的问题是:是它们在枚举通过访问代码完成,而不是访问者代码的模式的
解决方案
访问者对象的是知道它访问的事物的结构需要。这是确定的,虽然。你的应该的写访问专门为操作每种类型的东西访问者知道如何访问。这使得访问者多少来决定是否真的要来参观,以什么顺序。
假设你有一棵树。一位观众可能会做一个前序遍历,人们可能会做一个中序遍历,还有一个访客可能会在叶子节点只采取行动。访问者类可以做所有这些事情,而不需要对树类的任何更改。
访问者知道的结构中,但是,这并不一定意味着访问者执行操作知道所有的结构。你可能会用的命令结合访问者的。给访问者对象的命令对象,并且访问者将调用它访问每个事物的命令。
如果你想有一个简单的操作,让收集给你的每个项目采取行动,那么你要收集,为自身提供的迭代器即可。呼吁迭代器给你每一件事情的功能。
如果你想遍历各种顺序树的节点,则树将需要提供多个迭代器。如果你要处理节点的顺序是树的不已经支持,你需要修改树类。
其他提示
是。被访问的对象可以做枚举(即在需要的儿童的呼叫)。这仍是被称为“访问者”模式(实际上,设计模式的访客的第一样本确实是这样)。我的制造的例子片段:
public void accept(Visitor visitor) {
for (Node n : children) {
n.accept(visitor);
}
}
注:探望子女,我们不能说visitor.visit(n);
。这是因为Java不动态地选择方法(基于运行时类的它的参数),但静态选择方法(通过它的参数的编译时类型)。
在短的话,我认为要列举的方式完成访问者模式是正交的。这是可以做到无论哪种方式,或没有枚举的。
我认为,游客需要知道的访问结构包括哪些要素。想知道汽车是由车轮和发动机。要知道他们究竟是如何结合是没有必要的,我想。考虑下面的例子。知情人知道访问对象的结构和执行枚举本身。外人不知道它和代表枚举的访问对象。
interface Visitable {
void accept(Visitor visitor);
}
class WorkingRoom implements Visitable {
public int number;
WorkingRoom(int number) {
this.number = number;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
class BossRoom implements Visitable {
public String bossName;
BossRoom(String bossName) {
this.bossName = bossName;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
interface Visitor{
void visit(WorkingRoom workingRoom);
void visit(BossRoom bossRoom);
void visit(Office office);
}
class Office implements Visitable{
public Visitable[] firstFloor;
public Visitable[] secondFloor;
public Visitable ceoRoom;
public Office(){
firstFloor = new Visitable[]{ new WorkingRoom(101),
new WorkingRoom(102),
new BossRoom("Jeff Atwood"),
new WorkingRoom(103)};
secondFloor = new Visitable[]{ new WorkingRoom(201),
new WorkingRoom(202),
new BossRoom("Joel Spolsky")};
ceoRoom = new BossRoom("Bill Gates");
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
public void showMeTheOffice(Visitor visitor, boolean sayPlease) {
// Office manager decides the order in which rooms are visited
for(int i=secondFloor.length-1; i >= 0; i--){
secondFloor[i].accept(visitor);
}
if (sayPlease){
ceoRoom.accept(visitor);
}
for (int i = 0; i < firstFloor.length; i++) {
firstFloor[i].accept(visitor);
}
}
}
class Insider implements Visitor{
public void visit(WorkingRoom workingRoom) {
System.out.println("I> This is working room #"+workingRoom.number);
}
public void visit(BossRoom bossRoom) {
System.out.println("I> Hi, "+bossRoom.bossName);
}
public void visit(Office office) {
// I know about office structure, so I'll just go to the 1st floor
for(int i=0;i<office.firstFloor.length;i++){
office.firstFloor[i].accept(this);
}
}
}
class Outsider implements Visitor{
public void visit(Office office) {
// I do not know about office structure, but I know they have a
// nice office manager
// I'll just ask to show me the office
office.showMeTheOffice(this, true);
}
public void visit(WorkingRoom workingRoom) {
System.out.println("O> Wow, room #"+workingRoom.number);
}
public void visit(BossRoom bossRoom) {
System.out.println("O> Oh, look, this is "+bossRoom.bossName);
}
}
public class Main{
public static void main(String[] args) {
Office office = new Office(); // visited structure
// visitor who knows about office structure
Insider employee = new Insider();
office.accept(employee);
System.out.println();
// visitor who does not know about exact office structure
// but knows something else
Outsider candidate = new Outsider();
office.accept(candidate);
// no enumeration at all, but still a visitor pattern
Visitable v = new BossRoom("Linus Torvalds");
v.accept(candidate);
}
}
我与访问者模式的广泛使用的一个项目,没有任何枚举的。我们有基本接口场和许多类实现它,像StringField,NumberField等很多时候,我们有基于字段类型做不同的事情,例如从DB,导出到XML等使其以不同的方式,负载我们可以定义在现场接口的方法,但是这将使它再加上项目的每一个功能 - 场差已经知道有关导出,导入,渲染到HTML和RTF等,我们也可以使用instanceof,但设置的可能实现现场接口类是随着时间改变,有可能添加新的字段类型和忘记添加
else if (field instanceof NewlyAddedFieldType) {...}
某处。所以我们决定使用访问者模式,它是像
Visitor v = new XMLExportVisitor(outputStream);
field.accept(v);
如任何外地执行需要具有方法
void accept(FieldVisitor visitor)
然后如果我添加新的实施领域的接口,我必须以某种方式实现它。一般而言,这是
visitor.visit(this);
,其中该设备是新添加的类。这迫使我补充
void visit(NewlyAddedClass visited);
要FieldVisitor接口,这点让我实现它,我们已经有充分的FieldVisitor实施。所以,如果我忘了做这个事情 - 我会得到编译器错误。 在这种情况下枚举,如果有的话,被访问的结构和游客外完成。但我仍然认为它是访问者模式的一个有效的情况下。 它的发生是有点困难实现,但更容易和安全使用。
在分层访问者模式解释了不同的方法,其中它增加了进入和离开事件水平。相关的讨论页面提出论据迭代是游客或在容器内。它包括使用外部迭代器这对我来说很有意义,如果你有一个普通的树和需要遍历不同的建议。
回顾我的 oofRep游客它有一个系列的水平的不同的类访问和方法内有迭代等:
void
oofRepVisitor::VisitViewHeaders(oofRepBandList& inBands)
{
VisitBandList(inBands);
}
void
oofRepVisitor::VisitBandList(oofRepBandList& inBands)
{
EnterLevel();
const unsigned long numBands = inBands.count();
for (unsigned long i=0; i<numBands; i++) {
oofRepBand* theBand = inBands.value(i);
assert(theBand);
VisitTypedBand(theBand);
}
LeaveLevel();
}
与超控
void
OOF_repXMLlayoutVisitor::VisitViewHeaders(oofRepBandList& inBands)
{
oofRepStreamEnv::out() << mIdentities.getIndentString();
if (inBands.keepTogether())
oofRepStreamEnv::out() << "<header>\n";
else // default is ON, and simplifies XML
oofRepStreamEnv::out() << "<header keepTogether='false'>\n";
VisitBandList(inBands);
oofRepStreamEnv::out()
<< mIdentities.getIndentString()
<< "</header>\n";
}