Шаблон проектирования для реализации по умолчанию с пустыми методами - PullRequest
21 голосов
/ 11 августа 2009

Существует ли конкретный шаблон проектирования , который описывает сценарий, в котором предусмотрена неабстрактная реализация по умолчанию, которая реализует все или некоторые методы интерфейса с пустыми реализациями 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()
    }
}

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

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

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

Ответы [ 9 ]

4 голосов
/ 11 августа 2009

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

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

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

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

EDIT

Более того, это не Заглушка или Макет : возможно, его можно спутать с заглушкой, но намерение другое.

2 голосов
/ 18 февраля 2016

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

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

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

Для получения более подробной информации посмотрите соответствующие вопросы по SE.

Принцип разделения интерфейса

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

2 голосов
/ 11 августа 2009

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

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

2 голосов
/ 11 августа 2009

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

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

Я уверен, что этот вопрос уже задавался?

Это звучит похоже нет? может быть стоит прочитать.

1 голос
/ 09 октября 2018

Этот шаблон был распространен в более старых версиях Java. Это Java 7 альтернатива методам по умолчанию в интерфейсах .

Джош Блох называет это скелетной реализацией . Хотя реализация скелета обычно абстрактна, вам не нужно заставлять клиентов создавать подкласс, если сам скелет достаточен.

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

1 голос
/ 22 января 2013

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

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

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

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() {}
}
0 голосов
/ 05 мая 2014

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

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

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

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

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

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

0 голосов
/ 11 августа 2009

Мне кажется, это наиболее близко к шаблону Special * или Null Object .

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

public void doEverything()
{
  doThis();
  doThat();
  done();
}
0 голосов
/ 11 августа 2009

Вы спрашиваете о шаблоне пустых объектов ?

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

...