2016-01-22 3 views
1

Звуков жуткого, да ...анонимных посетителей

Я занимаюсь разработкой GUI-ориентированным приложения, которое делает интенсивное использование Visitor Pattern. Я использовал этот подход, потому что для меня важно обрабатывать кучу графических элементов в классах, хотя сами классы должны действовать как простые объекты данных. В этом отношении они полностью агностичны для множества сценариев, которым они подвержены в моей логике приложений.

Проблема, с которой я сталкиваюсь с этим выбором дизайна, заключается в том, что по мере того, как мое приложение растет, я обнаружил, что вынужден сделать постоянные распределения времени исполнения anonymous Visitor-реализациями, чтобы описать свой классный код в телах методов. Поскольку многие из них зависят от параметров, предоставленных во время вызова, я не могу извлечь многие из них для реализации многократного использования static.

Вот пример использования объекта Shaker, переданного во время выполнения, для выполнения операций только по типам Button.

private abstract class Graphical implements Visitor.Dispatch { 
    /* Position. */ 
    private int X; 
    private int Y; 
}; 

private final class Button extends Graphical { 
    @Override public final void onVisit(final Visitor pVisitor) { pVisitor.onReceived(this); } }; 

private final class ScrollBar extends Graphical { 
    @Override public final void onVisit(final Visitor pVisitor) { pVisitor.onReceived(this); } 
}; 

public static interface Visitor { 
    /* Adapter. */ 
    public static class Adapter implements Visitor { 
     @Override public void onReceived( Button pButton) { } 
     @Override public void onReceived(ScrollBar pScrollBar) { } 
    }; 
    /* Dispatch Method. */ 
    public static interface Dispatch { 
     public abstract void onVisit(final Visitor pVisitor); 
    }; 
    /* Visitor Implementations. */ 
    public abstract void onReceived(final Button pButton); 
    public abstract void onReceived(final ScrollBar pScrollBar); 
}; 

/* Iterates through a List of Graphicals and Shakes a Button. */ 
public static void onShakeButtons(final List<Graphical> pGraphicals, final Shaker pShaker) { 
    /* Allocate a Visitor. */ 
    final Visitor.Adapter lVisitor = new Visitor.Adapter() { @Override public void onReceived(final Button pButton) { 
     /* Shake the Button! */ 
     pShaker.onShake(pButton); 
    } }; 
    /* Iterate the Graphicals. */ 
    for(final Graphical lGraphical : pGraphicals) { lGraphical.onVisit(lVisitor); } 
} 

Может ли кто-нибудь предложить какие-либо предложения о том, как уменьшить количество распределений, которые я делаю? Или у меня есть реальное непонимание того, как шаблон должен применяться?

+0

Можете ли вы показать пример типичного кода? – Fildor

+0

И в чем проблема с созданием объектов? Java является объектом OO. Создание объектов является нормальным, ожидаемым и быстрым. Есть ли конкретная проблема? –

+0

Если вы используете анонимных посетителей много, вы должны рассмотреть возможность использования lambdas в Java 8, поскольку они, как правило, проще и чище. –

ответ

1

Есть опция. Вы можете создавать контейнеры для своего нестатического объекта внутри своего посетителя и обновлять эти контейнеры новыми нестатическими объектами и повторно использовать посетителя.

public class ConcreteVisitor extends Visitor { 

     private final AtomicReference<MyClass> mValue_1 = new AtomicReference<MyClass>(); 

     private final AtomicReference<SomeClass> mValue_2 = new AtomicReference<SomeClass>(); 

     public void updateVisitor(MyClass newMyClass, SomeClass newSomeClass) { 
      mValue_1.set(newMyClass) 
      mValue_2.set(newSomeClass) 
     } 

     @Override 
     public void visitElement_1(Element_1 element) { 
      // use your updated values here 
     } 

     @Override 
     public void visitElement_2(Element_2 element) { 
      // use your updated values here 
     } 
    } 

Если вам необходимо повторно посетитель, Вы просто обновить значения, а затем запустить его снова:

// You create it only once: 
    Visitor concreteVisitor = new ConcreteVisitor(); 

    // and reuse it all the time 
    concreteVisitor.updateVisitor(newMyClass, newSomeClass); 
    concreteVisitor.visitElement(element); 

Я использую AtomicReference в качестве контейнера, но может использовать свой собственный класс контейнера.

+0

Это хорошая идея, хотя я думаю, что она может быть немного негибкой (мне нужно будет выделить несколько конкретных реализаций для каждой операции, из которых существует много типов.) Также у меня есть опасения относительно любых долгоживущих ссылок, которые будет сохраняться в редко используемых вызовах. –

Смежные вопросы