Я реализую парсер в java.
Данные, которые я анализирую, имеют разные типы записей. Допустим, это записи типа A, B, C, ... У этих записей есть некоторые общие атрибуты. поэтому я думаю об интерфейсе Record, который будут реализовывать все записи A, B, C. Данные в файле будут такими:
A
B
B
C
C
C
...
X
Y
Z
Думаю иметь итератор записей. но это не будет типобезопасным. так как я могу иметь только
interface Record {
String getRecordName();
RecordType recordType();
}
class A implements Record {
@Override
String getRecordName() {...}
// record type 'A' specific methods/fields here
}
class B implements Record{
@Override
String getRecordName() {...}
// record type 'B' specific methods/fields..
}
class Parser implements Iterable<Record> {
boolean hasNext() {...}
// user has to examine record type and cast
Record next() { ...}
}
Есть ли способ обойти эту проблему? Может ли здесь быть полезен шаблон посетителя?
Редактировать: Поскольку то, что у меня есть, представляет собой поток записей (разных типов), мне все равно нужны функции композиции. как у обычного потока (например, карта, фильтр, takeWhile и т. д.)
Редактировать : Поразмыслив над шаблонами посетителей, я думаю, что у меня возникла другая идея. Интерфейс записи будет иметь метод accept (Visitor), а next () просто вернет Record (фактическим типом будет конкретный тип записи). Клиентская сторона реализует посетителя и переходит к методу принятия.
interface Record {
interface Visitor<R> {
<R> visit(A a);
<R> visit(B b);
}
// add accept method
<R> R accept(Visitor<R> v);
}
class A implements Record {
@Override
public <R> R accept(Visitor<R> v) {
return v.visit(this);
}
}
// client code; r could be A|B
Record r = parser.next();
String s = r.accept(new Visitor<String>() { ... });
Да, шаблон посетителя обычно используется в парсерах.
"... это не будет типобезопасным ..." не могли бы вы объяснить, почему он не будет безопасным по типу?
Да, шаблон посетителя - это именно то, что вам нужно. Не используйте instanceof.
@EmreAcar, да, я подумал об этом. но их много, и я не уверен, что это лучший способ. в языках программирования FP сопоставление с образцом считается идиоматическим.
Просто чтобы быть уверенным, что все находятся на одной странице - эти записи также имеют разную функциональность? Необходимо знать, какая запись А, Б и т. д.? Потому что в противном случае вы можете просто использовать интерфейс Record без преобразования в подклассы.
@kutschkem Да, разные записи типы имеют разный функционал.
@Nyan Вы планируете использовать только один класс Parser? Что делает метод next? Проверяет ли он тип записи и создает ли соответствующий экземпляр подкласса? Как он узнает, что это за тип записи? И последнее, но не менее важное: насколько важно иметь один объект домена под названием Record, который имеет все возможные атрибуты?
@CKing только один класс парсера. Метод next вернет следующую запись, запись может быть любой конкретной записью. (Аналогично типу Variant в языках программирования FP).
@Nyan Насколько важно иметь один объект Record, содержащий все атрибуты? Это позволяет как парсеру, так и клиенту избежать необходимости проверять типы записей!
@CKing Это было бы очень плохо, поскольку между разными типами есть существенная разница.
@Nyan Не совсем уверен, сколько ценности добавляет String s = r.accept(new Visitor<String>() { ... });. Я бы предпочел просто использовать кастинг, потому что 1) Просить клиента вызвать метод accept кажется мне неприятным. 2) Вам необходимо добавить новый метод visit для каждого нового типа записи.




Да: это называется шаблоном посетителя:
public interface RecordVisitor {
void acceptA(A record);
void acceptB(B record);
...
}
public class Parser {
public void parse(Reader reader, RecordVisitor visitor) {
....
}
}
...
parser.parse(reader, new RecordVisitor() {
@Override
void acceptA(A record) {
...
}
@Override
void acceptB(B record) {
...
}
...
});
...
Это не выглядит масштабируемым. Каждый раз, когда вы добавляете новый тип записи, нужно изменять интерфейс и (все) реализацию (и). Может быть, лучше было бы сочетание шаблона посетителя и цепочки ответственности.
@ Перемасштабируемость Turing85: вот почему такой код часто генерируется (для разумно развитого DSL) из определения грамматики. Например, ANTLR будет генерировать очень больших посетителей, которые действительно было бы довольно громоздко писать от руки.
Что касается масштабируемости, поможет ли алгебра объектов? в случае, если есть новый тип записи.
@ Нян, я не понимаю, как. В любом случае, если вы добавите больше типов записей, вы захотите обработать их, поэтому я не думаю, что это проблема.
вы пробовали "экземпляр"?