2012-06-18 4 views
3

Предположим, что у вас есть иерархия классов Java около 30 классов с базовым классом BaseClass и двумя основными подклассами (SubclassA, SubclassB) с несколькими подклассами каждый. Некоторые из этих подклассов имеют определенное поведение. Предположим, вы можете «вытолкнуть» их, изменив свое состояние. (Это новое требование добавление поведения к существующей иерархии. «Poke» не имеет смысла для большинства классов.)Дополнительный интерфейс Java в иерархии классов

interface Pokeable { 
    void poke(); 
    int getTimesPoked(); 
} 


public class Pokey extends SubclassB 
implements Pokeable { 
    private int timesPoked = 0; 
    public void poke() { 
    timesPoked++; 
    } 
    public int getTimesPoked() { 
    return timesPoked; 
    } 
} 

Если это будет сделано путем внедрения Pokeable только в тех классах, которые нуждаются в ней, а затем делать во всем коде, который должен вызывать любой объект, который подкачивается?

public void process(BaseClass b) { 
    if (b instanceof Pokeable) { 
    ((Pokeable)b).poke(); 
    } 
} 

Или должно быть реализовано всю иерархию. Подкачивается ради немногих, которые действительно являются Pokeable?

interface Pokeable { 
    void poke(); 
    int getTimesPoked(); 
    boolean isReallyPokeable(); 
} 

public class BaseClass implements Pokeable { 
    public void poke() {} 
    public int getTimesPoked() { return 0; } 
    public boolean isReallyPokeable() { return false;} 
} 

public class Pokey { 
    private int timesPoked = 0; 
    @Override 
    public void poke() { 
    timesPoked++; 
    } 
    @Override 
    public int getTimesPoked() { 
    return timesPoked; 
    } 
    @Override 
    public boolean isReallyPokeable() { 
    return true; 
    } 
} 

public void process(BaseClass b) { 
    b.poke(); 
} 

Редактировать добавлено: Это своего рода проблема с двойной отправкой. Если код «покер» что-то делает для объекта, он должен вызывать «poke()», если объект «подкачивается», но не может, если нет. Независимо от того, что вы «ткните()» или нет, зависит от того, хочет ли что-то совать и принимает ли объект за то, что он ткнул. Я мог бы использовать шаблон посетителя, но это, похоже, усложняет ситуацию.

+1

Нет ли уровень в иерархии, где вы могли бы решить, если классы сильфонные являются poakable? Как бы то ни было, эти классы должны быть подвержены промывке только для тестирования? – Morfic

+0

К сожалению нет. Большинство подклассов SubclassA Pokeable. Несколько подклассов SubclassB являются Pokeable. Подкласс A и подкласс B очень разные, и Pokeability нельзя учесть без множественного наследования, чего нет у Java. –

+0

В этом случае, возможно, вы могли бы попробовать композицию над наследованием, чтобы отделить «базовые классы poakeable» и «базовые классы, отличные от poakeable». Краткое описание того, как вы собираетесь совать классы, может помочь в разработке более сжатого решения. – Morfic

ответ

4

Если класс не pokable, я бы не рекомендовал его реализации интерфейса Pokeable, просто потому, что это будет путать.

Возьмите один из следующих подходов.

  • Создать абстрактный или конкретный подкласс BaseClass, который реализует Pokable, и есть все ваши к Pokeable подклассы Бе продлить. Этот подход хорошо работает, если poke() ing достигается по той же логике во всех реализующих классах.
  • Пусть каждый подкласс реализовать Pokeable индивидуально
+0

Гораздо лучший ответ, чем мой. +1 – BlackVegetable

+0

К сожалению, SubclassA/SubclassB - одно измерение; Pokeable/non-Pikeable - другое измерение.Просто для угадывания чисел, 20 являются Pokeable SubclassA, 5 являются не подкачиваемыми SubclassA, 5 являются подклассом SubclassB, 30 являются не подкачиваемыми SubclassB. –

+0

Как насчет: BaseClass не реализует Pokeable, но все равно ничего не делает с помощью методов poke() и getTimesPoked(). Подкидывающиеся подклассы перекрывают эти два. процесс (BaseClass b) может вызывать b.poke() без использования instanceof. Подклассы подкачки реализуют Pokeable; другие - нет. Кажется, что это работает, но почему-то что-то кажется неправильным в отношении стиля, поскольку «реализует Pokeable» также может быть комментарием «// реализует Pikeable». –

0

Ваши подклассы могут быть абстрактными, если вы не хотите внедрять все методы родительского класса. Но ....

Или должно быть реализовано всю иерархию. Подкачивается ради несколько, которые действительно являются Pikeable?

Определенно нет ... Классы, которые не подкачиваются, не должны выполнять подкачиваемый интерфейс.

Если это будет сделано путем внедрения Pokeable только в тех классах , что нужно, а затем, выполнив следующие действия во всем коде, который должен совать любой объект, который pokeable?

Это немного лучшая модель ... Однако это очень процедурный дизайн.

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

Можете ли вы зарегистрировать классы подкастов в диспетчере событий? ... Итак, когда происходит определенное событие, все классы трясутся?

+0

Фактически нет. В реальном приложении мы создаем SubclassA, когда он не должен быть одним из подклассов SubclassA. –

+0

«диспетчер событий»: это немного сложнее. Вещь, делающая «выталкивание», - это вещь, которая что-то делает для определенного объекта, так что за один раз ткнул только один объект. –

2

Я думаю, что метод, называемый «isReallyX», является предупреждающим знаком. Если кто-то взглянет на класс с первого взгляда и увидит, что он «Pikeable», он может попытаться высунуть его и в итоге неожиданно поступить, потому что это не действительно pokeable.

Я бы свой прежний подход у него не вводит в заблуждение внешних программистов (или себя после двух месяцев игнорируя этот код!)

+0

Метод 'isReallyPokeable' является сомнительным, но' instanceof' даже больше. Если у вас есть типы 'A',' B: A', 'C: B', а также версии' Pikeable' каждого, не будет ни одного типа, который бы воплощал концепцию Pikeable B, поскольку Pikeable C doesn ' t наследуется от Pokeable B, но вместо этого является Pokeable и наследуется от C (который не подкачивает и наследует от B). Если A включает методы Poke и isReallyPokeable, а один имеет набор из B и не позволяет добавлять что-либо, что не является Pokeable, то можно использовать методы «Pokey» для вещей в этой коллекции напрямую. – supercat

+0

@supercat Возможно, вы только что взорвали мой разум. – BlackVegetable

+0

Моя точка зрения заключалась в том, что проблемы реального мира не всегда выстраиваются в чистоту с наследованием; если известно, когда класс написан, что некоторые производные классы будут реализовывать какую-то функциональность, другие не будут, а те, кто реализует функциональность, не будут использовать общий базовый класс, тогда в базовый класс будут включены методы для этой функции, а также метод скажем, поддерживается ли это «менее злой», чем требовать, чтобы клиентский код использовал проверки 'instanceof' и типы. – supercat

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