#java #visitor-pattern
#java #посетитель-шаблон
Вопрос:
Вот часть моего Java-кода
public List<OBJ> a = new ArrayList<OBJ>();
public String A;
public String B;
public String C;
for (OBJ o : a) {
// .... TODO
}
Итак, у меня есть интерфейс OBJ, и есть три объекта, которые реализуют OBJ, скажем, X, Y, Z. Поэтому я сохраняю объекты X / Y / Z в списке a. Теперь скажем, что я хочу пройти цикл, и если o имеет экземпляр X, сохраните значение X.в A, если Y, сохраните значение Y. в B, а если Z, сохраните значение Z. в C. Итак, проблема в том, как на самом деле определить, какой тип объекта o (X, Y, Z) для сохранения их значений в правильной строке.
ПРИМЕЧАНИЕ: я хочу использовать шаблон Visitor или что-то в этом роде, но я на самом деле не очень хорошо разбираюсь в этом, поэтому прошу вашей помощи.
Это означает, что НЕТ Instanceof (ов) или приведения типов и НЕТ выделенных методов, таких как
interface OBJ {
void blah();
}
class X implements OBJ {
public void blah();
} // etc
Спасибо! Я действительно хочу избавиться от этого аспекта импорта программного обеспечения!
Эй, вау, спасибо за подробные и быстрые ответы, но моя ситуация немного сложнее, и извините, что я не добавил это раньше.
Таким образом, строки A, B, C фактически размещены в другом классе, например
class ARGH {
public List<OBJ> a = new ArrayList<OBJ>();
public String A;
public String B;
public String C;
//invisible constructor here
public String toString () {
for (OBJ o : a) {
// .... TODO
}
return "some string"
}
}
public void main (String[] args) {
ARGH argh = new ARGH();
// Setup some X, Y, Z objects and their values here
String D = argh.toString();
// Do something to D
}
Таким образом, строки и список на самом деле не являются глобальными переменными, поэтому я не думаю, что это сработает:
ObjVisitor v = new ObjVisitor() {
@Override
public void visit(X x) {
A = x.value();
}
// And so on.
}
Я предполагаю, что мне нужно каким-то образом передать строку A, B, C в метод visit, но я не знаю, как это сделать, и при этом оставаться с шаблоном Visitor.
Комментарии:
1. Я не уверен, что вы можете это сделать, передача A, B и C в методы не будет работать из-за их неизменности. Вы могли бы создать A, B и C StringBuilders и передать их в качестве параметров конструктору ObjVisitor, тогда у него была бы ссылка на эти StringBuilders?
Ответ №1:
В ореховой скорлупе вы бы поступили так:
- Создайте интерфейс Visitor
ObjVisitor
с однимvisit
методом для каждого типа. - Добавьте аннотацию
accept(ObjVisitor v)
кOBJ
. - Добавьте an
accept(ObjVisitor v) { v.visit(this); }
к каждойOBJ
реализации. - Вызов
o.accept(yourVisitorImpl)
в цикле.
Вы действительно получили некоторый код от Bringer128. Я немного доработал и добавил String
-stuff .
import java.util.*;
interface OBJ {
String accept(ObjVisitor v);
}
interface ObjVisitor {
String visit(X x);
String visit(Y y);
String visit(Z z);
}
class X implements OBJ {
public String accept(ObjVisitor v){ return v.visit(this); }
}
class Y implements OBJ {
public String accept(ObjVisitor v) { return v.visit(this); }
}
class Z implements OBJ {
public String accept(ObjVisitor v) { return v.visit(this); }
}
Использование:
class Test {
public static void main(String[] args) {
List<OBJ> objs = Arrays.asList(new Z(), new X());
ObjVisitor toStringVisitor = new ObjVisitor() {
public String visit(X x) { return "X object"; }
public String visit(Y y) { return "Y object"; }
public String visit(Z z) { return "Z object"; }
};
String result = "";
for (OBJ o : objs)
result = o.accept(toStringVisitor) "n";
System.out.println(result);
// Prints
// Z object
// X object
}
}
Альтернативой (возможно, лучшим подходом) было бы позволить реализации visitor поддерживать StringBuilder, позволить методам visit возвращать void, а после цикла просто вызвать stringVisitor.getCurrentString()
или что-то в этом роде.
Ответ №2:
aioobe разъяснил это для вас, но вот как будет выглядеть реализация.
interface OBJ {
void blah();
// New method!
void accept(ObjVisitor v);
}
class X implements OBJ {
public void blah() {}
@Override
public void accept(ObjVisitor v) {
v.visit(this);
}
}
interface ObjVisitor {
public void visit(X x);
public void visit(Y y);
}
Теперь используйте его:
public List<OBJ> a = new ArrayList<OBJ>();
public String A;
public String B;
public String C;
public void myMethod() {
ObjVisitor v = new ObjVisitor() {
@Override
public void visit(X x) {
A = x.value();
}
// And so on.
}
for (OBJ o : a) {
o.accept(v);
}
}