2015-12-30 5 views
1

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

void exec(int parameter); 

против

void exec(); 

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

\ 1. Используйте instanceof:

int parameter = ... 
if (a instanceof NewInterface) 
    ((NewInterface) a).exec(parameter); 
else 
    ((OldInterface) a).exec(); 

Преимущества этого является то, что NewInterface и OldInterface могут быть независимыми интерфейсами. Когда разработчик пишет новый класс, может быть более очевидным, какие методы переопределить, а переопределение неправильного метода приведет к ошибке времени компиляции.

\ 2. Используйте единый интерфейс с обеими методами, определенных и родительским абстрактным классом, который перенаправляет от одного метода к другому:

abstract class Common { 
    abstract void exec(); 
    void exec(int param) { exec(); } 
} 

Это позволяет избежать instanceof, что считается плохим в некоторых дискуссиях, но теперь в каждом новом классе мы должны добавить странный окурок:

// This is not used anymore 
void exec() { }; 
// This is a real functionality 
void exec(int param) { ... 

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

Должен ли я использовать какой-либо третий подход, или это тот случай, когда использование экземпляра является разумным?

+0

У вас есть доступ ко всей базе данных, использующей ваш метод? – user3707125

+0

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

+1

@ h22, но это правильная вещь. Контракт интерфейса говорит о том, что exec() принимает параметр, и это зависит от реализации, чтобы что-то сделать с ним или игнорировать его. –

ответ

2

В случае, если вы используете Java 8, вы можете легко реализовать его в интерфейсе с помощью default implementation:

public interface MyInterface { 

    void exec(); 

    default void exec(int param) { 
     exec(); 
    } 
} 

exec(int) естественно может быть преодолено конкретными классами.

Другим решением является наличие NewInterface extends OldInterface. Затем новые классы реализуют NewInterface#exec(int) и OldInterface#exec(), новые клиенты могут выбрать способ вызова, а старые клиенты знают только OldInterface.