Подтвердить что ты не робот

Шаблон проектирования для реализации по умолчанию с пустыми методами

Существует ли специальный шаблон , описывающий сценарий, в котором предоставляется не абстрактная реализация по умолчанию, которая реализует все или некоторые из методов интерфейса с пустым реализацией NO-OP. Это делается с целью облегчения подклассов с бременем внедрения методов, которые они сами могут не использовать/использовать:

public interface MyInterface {
    public void doThis();
    public void doThat();
    public void done();
}

public class MyClass implements MyInterface {
    public void doThis() {
        // NO-OP
    }
    public void doThat() {
        // NO-OP
    }
    public void done() {
        // Some standard implementation
    }
}

public class MuSubClass extends MyClass {
    public void doThat() {
        // Subclass only cares about doThat()
    }
}

Я видел этот шаблон несколько раз, включая Java DefaultHandler в среде SAX и MouseAdapter. В некоторых случаях такие классы называются адаптерами, но у меня создалось впечатление, что шаблон адаптера переводится между двумя разными интерфейсами.

Учитывая, что в этих случаях существует только один объявленный интерфейс, который переводится в подмножество undefined этого интерфейса - я не понимаю, как это находится в духе шаблона адаптера.

Кроме того, я не совсем понимаю, как это относится к NullObject pattern, так как некоторые методы могут иметь реализацию и NullObject традиционно является одиночным.

4b9b3361

Ответ 1

Нет шаблонов проектирования для реализации по умолчанию.

Обычно я добавляю префикс DoNothing к имени класса. В зависимости от этого я использую также Base или Default (последний широко используется). Вероятно, MouseAdapter следует называть DefaultMouseListener.

В случае, если вам небезразлично, вы можете систематизировать интерфейс с простым DynamicProxy, вы должны вернуть только "хорошее" значение по умолчанию (null для объекта, 0 для числа и т.д.).

Кстати, это очень хороший вопрос.

ИЗМЕНИТЬ

Кроме того, это не Stub или Mock: возможно, его можно путать с заглушкой, но намерение отличается.

Ответ 2

Я видел этот проект, используемый в spring, где у них есть класс с именем FlowExecutionListenerAdapter, который сохраняет реализацию всех операций FlowExecutionListener.

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

Я уверен, что этот вопрос был задан раньше?

Звучит как аналогичный нет? возможно, стоит прочитать.

Ответ 3

Он также используется в Swing (WindowAdapter, который реализует WindowListener). Это только удобный адаптер, вам нужно только определить 1-2 метода таким образом, чтобы иметь полезный windowlistener. Это действительно экземпляр шаблона адаптера, также показывает силу абстрактных классов. Это даже пример, чтобы проиллюстрировать, почему несколько наследований реализации иногда могут быть полезны.

Что касается обычных шаблонов проектирования, в методе Temlate вы можете определить операции с крючками, которые могут быть переопределены (в отличие от абстрактных методов, которые должны быть), но значение по умолчанию (как правило, NO-OP) также имеет смысл.

Ответ 4

Отличный вопрос.

Я начал использовать NoOp в качестве префикса имени класса для этого шаблона. Это короткое, ясное и не перегруженное (например, Empty [ничего не содержит?], Null [шаблон Null Object, который отличается?], Abstract [Предоставляет ли он некоторую реализацию?] Или Base [ Предоставляет ли она некоторую реализацию?]).

Я могу написать этот стиль класса, когда у меня есть сторонний API, который предоставляет "Крючки" для isntrumentation во время сложной операции. Рассмотрим следующие два класса, предоставляемые библиотекой:

public class LongRunningActionRunner {
    public void runSomethingLong(DecisionListener cdh) {
        // ...
    }
}

public interface DecisionListener {
    public void beforeFooHook();
    public void afterFooHook();
    public void beforeBarHook();
    public void afterBarHook();
    public void beforeBazHook();
    public void afterBazHook();
}

В этом случае вы можете править классом с использованием этого шаблона следующим образом:

public class NoOpDecisionListener implements DecisionListener {
    @Override public Something beforeFooHook() {}
    @Override public Something afterFooHook() {}
    @Override public Something beforeBarHook() {}
    @Override public Something afterBarHook() {}
    @Override public Something beforeBazHook() {}
    @Override public Something afterBazHook() {}
}

Ответ 5

Вам следует придерживаться другого принципа дизайна: принцип разделения интерфейса

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

Вы не должны реализовывать БОЛЬШЕ И вы не должны использовать LESS

Посмотрите на связанные вопросы SE для более подробной информации.

Принцип сегрегации интерфейса

Принцип сегрегации интерфейса - программа для интерфейса

Ответ 6

Вы спрашиваете о Null Object Pattern?

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

Ответ 7

Мне кажется, это ближе всего к Специальный случай или Null Объект.

В ваших обновлениях предлагается что-то похожее на Template Method ожидать, что у вас нет единого метода, который вызывает каждый метод шаблона, например

public void doEverything()
{
  doThis();
  doThat();
  done();
}

Ответ 8

Я считаю, что Мартин Фаулер назвал бы этот шаблон нулевым объектом. В своей книге Рефакторинга [1] Мартин вводит нулевые объекты как таковые:

Сущность полиморфизма заключается в том, что вместо того, чтобы спрашивать объект, что введите его, а затем вызовите какое-то поведение, основанное на ответе, вы просто вызовите поведение. Объект, в зависимости от его типа, выполняет правильная вещь. Одно из менее интуитивных мест для этого - это то, где вы имеют нулевое значение в поле.

Позже он добавляет: "Вы выигрываете, когда многие клиенты хотят делать то же самое, они могут просто полагаться на стандартное поведение по умолчанию". Он также вводит метод isNull() для клиентов, требующих вариантов поведения.

Я бы согласился, что иногда вижу (часто абстрактную) реализацию, называемую адаптером. Например, в платформе Android AnimatorListenerAdapter (исходный код здесь) описывается как:

Этот класс адаптера предоставляет пустые реализации методов из Animator.AnimatorListener. Любой пользовательский прослушиватель, который заботится только о подмножестве методов этого слушателя, может просто подклассифицировать этот класс адаптера, а не напрямую реализовать интерфейс.

[1] "Рефакторинг: улучшение дизайна существующего кода", глава 9, "Упрощение условных выражений", "Ввести нулевой объект".