Когда использовать дженерики?

Вникая в путаницу здесь, когда нужно использовать дженерики:

Скажем, у меня есть:

public class Honda implements ICar(){
}

public class Opel implements ICar(){
}

следует использовать:

public class Person{
    ICar car;
    .
    .
    public Person (ICar c){
        car = c;
    }
}

или

public class Person<T extends ICar>{
    T car;
    .
    .
    public Person(T c){
        car = c;
    }
}

или зависит от выполняемых задач?

РЕДАКТИРОВАТЬ: Так что, общие для только связей агрегации (контейнеры и т.д.)?

EDIT: Это может помочь:

Java Generics?

Я думаю, что я спрашиваю, являются ли генериками только для использования с коллекциями?

Ответы

Ответ 1

Обычно человек не параметризуется типом автомобиля. Только очень раздражающие люди определяются их автомобилем. Люди тоже меняют машины (со временем). Поэтому я не буду параметризовать класс, если только для семантики.

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

Ответ 2

Различие не всегда четкое, но вот несколько подсказок:

  • Попробуйте представить их как "параметры типа" (какие они есть). Они связаны с классом, но они не обязательно связаны с ним. (Посмотрите, например, на структуру коллекций.)
  • Параметры типа могут использоваться только в том случае, если они не изменяются в течение всего жизненного цикла объекта. Это звучит совершенно очевидно, но это очень удобное правило, чтобы решить, когда НЕ использовать дженерики. (Например, человек, который может менять автомобили.)
  • С другой стороны, если не многие экземпляры будут использовать параметр типа, если он слишком необязательный, это тоже не очень хорошая идея. (Многие люди могут вообще не иметь машин.)

И, наконец, общая мысль, которую я нашел очень полезной: если вы не уверены, не бойтесь прототипировать ее. Напишите код в обоих направлениях и проверьте, какой из них проще и понятнее. Покажите это кому-то еще без каких-либо объяснений или, может быть, подождите один или два дня, а затем перечитайте код самостоятельно. Затем выбросьте другого. Выброс кода хорош.

Ответ 3

Вам нужна версия generics, если у вас есть какие-либо методы, которые принимают или возвращают все, что связано с T, или если другие люди могут получить доступ к вашему полю car. (Поскольку вы не показывали никаких методов, мы не можем сказать.)

Например, с версией generics у вас может быть такой метод, как T someMethod();, тогда, когда у кого-то есть Person<Honda>, они знают, что могут вернуть Honda, когда они назовут someMethod, а не какие-то неизвестные тип автомобиля, если у вас не было дженериков.

Аналогично, с версией generics у вас может быть такой метод, как void anotherMethod(T anotherCar);, тогда, когда у кого-то есть Person<Honda>, это заставляет их передавать Honda этому методу вместо любого автомобиля.

Таким образом, в основном, с общим классом вы можете поместить ограничения на использование объекта позже (вызовы методов и т.д.). Если конструктор - это единственное место, где вы используете T, и вам не нужно использовать T в любых методах или полях, то да, для этого нет смысла.

Ответ 4

Это связано с использованием Inheritance to the Composition.

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

http://www.artima.com/objectsandjava/webuscript/CompoInherit1.html http://en.wikipedia.org/wiki/Composition_over_inheritance

Ответ 5

Я бы склонялся к композиции (то, что вы называете динамической привязкой), особенно в том случае, если вы используете. Человек не является типом ICar, поэтому использование дженериков здесь немного странно (для меня все равно). Я бы использовал дженерики как способ сказать "Контейнер для ICar", как в Garage, хотя в этом случае я мог бы просто использовать тип коллекции в качестве переменной или расширить тип коллекции, если это действительно необходимо.

Ответ 6

Я бы предложил сначала сосредоточиться на семантике:

Предположим, что у вас есть классы Bmw и Toyota, реализующие интерфейс ICar, затем задайте этот вопрос: может ли Person изменить его автомобиль или это будет другой человек, если он это сделает?

Подход generics заставит вас создать новый экземпляр Person, если по какой-то причине вам нужно изменить значение атрибута car от Toyota до Bmw в экземпляре существующего лица и, таким образом, это новый человек будет отличаться от предыдущего. Конечно, вы можете создать первый экземпляр Person как Person<ICar> вместо того, чтобы подключить его к определенному классу автомобилей, но зачем использовать generics?