Унаследованный код моей компании страдает от преобладающего использования instanceof switch-casing в виде:
if(object instanceof TypeA) {
TypeA typeA = (TypeA) object;
...
...
}
else if(object instanceof TypeB) {
TypeB typeB = (TypeB) object;
...
...
}
...
...
Что еще хуже, некоторые из рассматриваемых классов TypeX на самом деле являются оболочками классов, найденных в сторонних библиотеках.
Предлагаемый подход с использованием шаблона дизайна посетителя и специальных оболочек шаблона дизайна посетителя в сторонних классах, как показано здесь (instanceof -> Visitor DP) и здесь (Visitor DP со сторонними классами) кажется хорошим подходом.
Однако во время сеанса проверки кода, на котором был предложен этот подход, вопрос о дополнительных накладных расходах стандартного кода, необходимого для каждого рефакторинга экземпляра переключателя, привел к отклонению этого механизма.
Я хотел бы исправить эту постоянную проблему, и я рассматриваю общий подход к проблеме:
Вспомогательный класс, который будет обертывать шаблон дизайна посетителя общими ссылками на посещенные объекты. Идея состоит в том, чтобы реализовать базовое ядро служебного класса посетителя один и только один раз и предоставить конкретные реализации поведения объекта TypeX там, где это необходимо, — возможно, даже повторное использование некоторых реализаций через объектно-ориентированное расширение классов, реализующих функциональность.
У меня вопрос - кто-нибудь здесь делал что-то подобное? Если нет - можете ли вы указать какие-либо плюсы/минусы, которые могут иметь значение?
РЕДАКТИРОВАТЬ: слишком много шаблонного кода = реализация шаблона дизайна посетителя специально для каждого экземпляра instanceof switch-case. Это явно избыточно и приведет к большому дублированию кода, если DP посетителя не реализовано с использованием дженериков.
Что касается универсальной утилиты DP для посетителей, я имел в виду:
Прежде всего, использование отражения с DP посетителя, как показано здесь.
Во-вторых, следующее использование дженериков (на основе рефлексивного посетителя):
public interface ReflectiveVisitor<GenericReturn,GenericMetaData>
{
public GenericReturn visit(Object o, GenericMetaData meta);
}
public interface ReflectiveVisitable<A,B>
{
public GenericReturn accept(Visitor visitor, GenericMetaData meta);
}
GenericReturn и GenericMetaData — это интерфейсы, предназначенные для предоставления любых дополнительных метаданных, необходимых для реализации конкретной логики, а также для обеспечения универсальности типов возвращаемых данных, возвращаемых посетителем DP.
Заранее спасибо!
РЕДАКТИРОВАТЬ: кодирование шаблона при рефакторинге от instanceof к посетителю:
Обычный вариант использования, который мне пришлось бы обрабатывать, — это instanceof switchcasing для выполнения отдельных вызовов API конкретных реализаций:
public class BoilerPlateExample
...
if(object instanceof TypeA) {
((TypeA) object).specificMethodTypeA(...)......;
}
else if(object instanceof TypeB) {
((TypeB) object).completeyDifferentTypeBMethod(...)......;
}
...
...
Что касается дизайна посетителя, справляющегося с этим?
public interface Visitor
{
// notice how I just binded my interface to a specific set of methods?
// this interface will have to be generic in order to avoid an influx of
// of dedicated interfaces
public void visit(TypeA typeA);
public void visit(TypeB typeB);
}
public interface Visitable
{
public void accept(Visitor visitor);
}
public class BoilerPlateExampleVisitable<T> implements Visitable
{
// This is basically a wrapper on the Types
private T typeX;
public BoilerPlateExampleVisitable (T typeX) {
this.typeX = typeX;
}
public void accept(Visitor visitor) {
visitor.visit(typeX);
}
}
public class BoilerPlateExampleVisitor implements Visitor
{
public void visit(TypeA typeA) {
typeA.specificMethodTypeA(...)......;
}
public void visit(TypeB typeB) {
typeB.completeyDifferentTypeBMethod(...)......;
}
}
public static final BoilerPlateExampleVisitor BOILER_PLATE_EXAMPLE_VISITOR = new BoilerPlateExampleVisitor();
public static void main(....) {
TypeA object = .....; // created by factory
BoilerPlateExampleVisitable boilerPlateVisitable = VisitableFactory.create(object); // created by dedicated factory, warning due to implicit generics
boilerPlateVisitable.accept(BOILER_PLATE_EXAMPLE_VISITOR);
}
instanceof
. Тот факт, что код в этой статье требует, чтобы методы назывались определенным образом, и молча завершается ошибкой, если есть опечатка, также ужасен. - person Radiodef   schedule 04.04.2018