2009-04-05 6 views
1

Вопрос о составе и ориентации объектов:Вопрос о составе Java

Я пытаюсь реализовать дополнительные функции для класса (Java TreeMap в качестве примера).

public class TreeMap<K,V> 
    extends AbstractMap<K,V> 
    implements NavigableMap<K,V>, Cloneable, Serializable 

Использование композиции является way to go on this, так что я должен был бы создать первый класс многоразовые переадресации, который будет обернуть функциональность класса, в то время как в то же самое время сделать это делать только то, что так, что он может будет использоваться в других местах в будущем.

public class ForwardingNavigableMap<K,V> implements NavigableMap<K,V> 
{ 
... 
} 

Я бы тогда приступить к созданию класса-оболочки, который наследуется вновь созданный reusable forwarding class, например так:

public class BetterTreeMap<K,V> extends ForwardingNavigableMap<K,V> 
{ 
/* some new cool features here */ 
} 

Что произойдет, если TreeMap содержит ряд тонкостей, которые мне нужны в мой класс, который может не быть частью интерфейса NavigableMap? Должен ли я тогда продолжить объявление моего собственного интерфейса для TreeMap и реализовать его в моем многоразовом классе? Любой вход здесь ценится.

ответ

1

Самый простой подход заключается просто расширить существующий класс

public class MyTreeMap<K,V> extends TreeMap<K,V> { 
    // add your overridden or extra methods here. 
} 

Я предлагаю вам не делать вещи более сложными, чем они должны быть.

Если это не подходит, возможно, вы могли бы объяснить, чего вы пытаетесь достичь.

+0

Я пытаюсь создать объект, ограничивающий иерархию для обнаружения столкновений в простой игре. Я не уверен, что TreeMap - это то, что я хочу, поэтому мне нужно будет его заменить позже, поэтому предпочтение композиции над наследованием (extends) – Andreas

+0

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

1

Если эти интересные новые функции будут реализованы на других структурах данных, которые вы будете использовать абсолютно.

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

1

Проблема в том, что в этом примере TreeMap действует как интерфейс. Вы можете рассматривать его как таковое, переопределяя все его методы для пересылки. Не похоже, что в пустом TreeMap существует много состояний. Однако это хрупкий подход, поскольку новые методы (или те, которые вы пропустили) не будут обрабатываться.

Возможно, ваш класс не обязательно должен быть Map. Вы можете создать интерфейс, соответствующий вашему коду, но asMap/asSortedMap/asNavigableMap для использования с библиотеками и неспецифическим кодом.

1

Что произойдет Если TreeMap содержит несколько прекрасных функций, которые мне нужны в моем классе, это может быть не так, как часть интерфейса NavigableMap?

Это проблема с использованием композиции в таких случаях. Если вы обнаружите, что создаете кучу методов-оболочек, которые ничего не делают, кроме вызова тех же методов в TreeMap, это аргумент в пользу наследования. Так что если у вас есть значительное количество методов, которые выглядят как

public Set<K> keySet() 
{ 
    return myTreeMap.keySet(); 
} 

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

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

2

Предполагая, что вы не собираетесь превращать это в пули API (это означает, что вы не отправляете его третьим сторонам и не ожидаете, что они его используют), вы можете сделать следующее.

Учитывая, что вам (возможно) требуется доступ к определенным методам TreeMap, но также может позже решить изменить наследование как нечто иное, чем TreeMap, если вы не пишете никакого кода, который зависит от того, какой класс является TreeMap (например, никогда не ссылайтесь на TreeMap, кроме «extends TreeMap»), тогда вы можете использовать extends. Для этого потребуется написать интерфейс, который предоставил методы TreeMap.

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

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

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

1

Поместите все свои новые методы в новый интерфейс и создайте класс, который также реализует этот интерфейс.

Здесь было бы

public class MyMap implements MyInterface, NavigableMap { 
... 
} 

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

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