Я перешел от Java 1.4 (предыдущая компания) к Java 1.6 (новая компания). Что я заметил, что в случае 1,4 большинство собственных платформ было определено с помощью интерфейсов и шаблонных шаблонов, тогда как с 1,6 большинство платформ определяется вокруг дженериков.
В то время как я все еще пытаюсь получить власть вокруг Дженериков, мой вопрос - действительно ли это - правильный подход дизайна? Интерфейсы делают Ваш дизайн более гибким/разъединяющим. Принимая во внимание, что Дженерики, безопасность типов реализации и осуществляют Вас для раздавания определенного типа класса. Действительно не помогает в разъединении Вашего кода. Это корректно?
Один пример -
public MyWizard extends SignupWizard<SignupSection, SignupObject, SignupListener, SignupView>{
}
вместо этого дизайн был бы более гибким, если бы это было..
public interface Wizardable{
public SignableSection getSection();
public SignableObject getSignableObject();
...
}
public MyWizard implements Wizardable{
....
}
Я бы не сказал, что что-то было чем-то вроде интерфейсов и дженериков, у каждого из которых свои потребности и разные способы использования. Использование общих параметров способом, указанным в исходном сообщении, служит нескольким целям. Он позволяет разработчикам определять базовые классы, составляющие типы объектов поля класса. Используя это, разработчик может принять объекты класса в качестве параметров, для которых он может использовать отражение для создания фактических объектов и установки полей, или просто принять весь объект для установки в первую очередь. Проблема, которая связана с необходимостью объектов класса вместо выполнения new T ()
или подобного, известна как стирание типа .
Еще одним преимуществом использования универсальных шаблонов является то, что вам не нужно постоянно приводить типы при использовании полей или методов из суперкласса - вы лично знаете их типы, но в Java нигде не хранится такая информация о типах. Дополнительным преимуществом является то, что все ваши методы получения / установки могут использовать общие параметры и предоставлять более разумный фронт другим объектам, которые полагаются на тот факт, что вы настроили специализированные поля в вышеупомянутом объекте.
Проблема с использованием интерфейсов для того же, что и универсальные, заключается в том, что вам нужны дополнительные методы для доступа к специализированным типам и их преобразования перед их возвратом (или проверкой входящих типов, а затем установкой полей для объектов). Это усложняет конструкцию и совсем не помогает с разделением.
Как я упоминал в комментарии, любые подклассы устанавливают эти параметры типа и ничего не предоставляют пользователю. Таким образом, у вас может быть что-то вроде class MegaSignupWizard extends RegistrationWizard
, и все остается совершенно корректным с MegaSignupWizard
, имеющим доступ к специализированным методам в классах без необходимости использования каких-либо специальных методов в классах. В ролях. Вот это круто :)
Generics позволяет вам реализовывать методы для общего типа, в то время как интерфейсы определяют только сигнатуры. Возможно, иногда ею злоупотребляют, чтобы действовать как черта Scala
, но в основном они служат двум разным целям. Если бы все было интерфейсом, будет много дублированного кода или делегирования некоторому вспомогательному классу.
Взгляните на Jung2, чтобы увидеть, где дженерики становятся действительно мощными. По сути, любой объект может быть вершиной или ребром, что позволяет реализовать некоторые действительно интересные идеи в сетевых алгоритмах. Вы не сможете сделать это с помощью одних лишь интерфейсов.
Я также не уверен, что ваше вышеприведенное использование выглядит хорошо. Если вы расширяетесь от объекта или реализуете интерфейс, вы не захотите передавать объекты таким образом. Дженерики используются для реализации класса с абстрактным типом, например, коллекции, который может действовать на что угодно. Что произойдет, если я передам SignupWizard
, что вполне допустимо?
Для этой конкретной идеи, возможно, вы действительно хотите использовать интерфейсы. Пусть интерфейс определяет wizardaction, каждый объект реализует его, а mywizard сможет .addaction(int position, wizardaction action). На самом деле это определенно проблема интерфейсов.
Я соглашусь с остальными - дженерики используются, когда они нужны библиотекам.
Я заметил, что многие новые фреймворки, как правило, используют аннотации вместо интерфейсов, но я не Я заметил, что они используют дженерики вместо интерфейсов (что бы это ни значило - объясните, пожалуйста, больше).
С помощью универсальных типов можно уменьшить некоторое дублирование кода и повысить безопасность типов, когда у вас есть один интерфейс с параметрами универсального типа, и один и тот же интерфейс будет работать для множества разных типов. Коллекции в пакете java.util - хороший пример того, когда можно использовать универсальные шаблоны.
Что касается аннотаций, иногда мне кажется, что ими злоупотребляют, и интерфейс был бы лучше - например, с интерфейсом легко узнать, какие параметры должен принимать метод, - но в других случаях аннотации более гибкие и мощные.