Вопрос о Java-композиции - PullRequest
       25

Вопрос о Java-композиции

1 голос
/ 05 апреля 2009

Вопрос о композиции и ориентации объекта:

Я пытаюсь реализовать больше возможностей для класса (например, Java TreeMap).

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

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

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

Затем я бы приступил к созданию класса-обертки, который наследует вновь созданный класс переадресации многократного использования , вот так:

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

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

Ответы [ 6 ]

2 голосов
/ 05 апреля 2009

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

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

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

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

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

1 голос
/ 05 апреля 2009

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

Вот это было бы

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

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

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

1 голос
/ 05 апреля 2009

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

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

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

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

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

1 голос
/ 05 апреля 2009

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

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

1 голос
/ 05 апреля 2009

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

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

1 голос
/ 05 апреля 2009

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

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

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

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

...