Java Generics and Design Patterns: не параметризация ссылки на общий тип всегда плохо?

StackOverflow https://stackoverflow.com/questions/7327209

Вопрос

Этот вопрос частично связан с моим последним вопрос.

У меня есть общий класс, представляющий коллекцию общих объектов:

public interface MyObject<N extends Number>{}

public interface MyCollecion<N extends Number> {
    public foo(MyObject<N> obj)
}

В моем дизайне эти коллекции объектов построены клиентским классом (давайте назовем его CollectionBuilder) с помощью абстрактного класса подхода:

public interface AbstractCollectionFactory {
    public abstract <N extends Number> MyCollection<MyObject<N>> createCollection(String collectionType);

}

Общие коллекции должны быть построены таким образом:

public class CollectionBuilder{
    AbstractCollectionFactory f;
    public void buildDoubleCollection(){

         MyCollection<MyObject<Double>> c = f.<Double>createCell("MyType");
    }
    public void buildIntegerCollection(){...}
}

ОК. Здесь все в порядке. CollectionBuilder знает, что такое общий бетонный тип для указания (в этом случае в два раза) и может построить правильно. Я могу скомпилировать это без предупреждения, и все должно работать нормально.

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

У меня есть еще один класс в моем приложении, который должен использовать коллекцию, созданную CollectionBuilder (давайте назовем этот класс userclass). Userclass:

  1. Не нужно знать, какой конкретный конкретный тип является его коллекцией (MyCollection<MyObject<Double>> или же MyCollection<MyObject<Integer>>).
  2. Выполните некоторые операции по этим коллекциям, ссылающиеся на некоторые методы, определенные в интерфейсе MyCollection.
  3. Я не хотел бы добавлять в него общий тип.

В описанной ситуации, что плохая идея не параметризует общий класс Mycollection Insive userclass?

public UserClass{
     MyCollection a;  //warning 
     MyCollection<?> b; //no warning

     public method(MyObject o){  //warning
          a.foo(b); //compile       
     }
     public method2(MyObject<?> o){
          b.foo(o); //error do not compile
     }
}

Компилятор Java всегда протестует с предупреждением, если я не укажу общий параметр. В любом случае, изнутри userclass я не знаю конкретный параметр (и я хотел бы не знать его) и даже объявить его "?" Не позволяйте мне позвонить в Method Foo на MyCollection.

Итак, вопрос:

  1. Не параметризация ссылки на общий тип всегда плохо?
  2. Если ответ в 1 нет, это правильная ситуация для этого не делать?
  3. Если ответ в 1 - это да, как я могу использовать метод MyCollection изнутри userClass, не зная их общих типов?
  4. У меня плохой дизайн?

Я надеюсь, что будет ясен. Я борюсь за эту проблему с дней, и понятия не имею. Помогите мне, пожалуйста.

Это было полезно?

Решение

  1. По словам Java Compiler, да. А также этот ответ Содержит много хороших моментов, почему. Лично я не согласен в некоторых ситуациях, особенно в случае использования Class обеспокоен (например, если у вас есть Map<Class, Object>) В таких случаях приходится всегда приступать <?> В конце «класса» просто ощущается как ненужная уточка и не делает код еще более читабельным.

    Идея иметь Class быть параметризованным на основе того, какой тип объекта он связан, всегда чувствовал себя немного сомнительным для меня. Точка Class состоит в том, чтобы иметь общий интерфейс, который можно использовать для получения информации о любом объекте (отражение ALA), независимо от его типа.

    Но я отступаю. Согласно Java Compiler и The Ineultors of Generic Types, вы всегда должны параметризовать свою ссылку, даже если вы используете только <?>.

  2. Непригодный. Хотя вы всегда не можете объявить информацию о какой -либо типах, а затем использовать @SuppressWarnings("unchecked") наряду с явным составом, чтобы сделать компилятор счастливым.

  3. Смотрите ответ богемя.

  4. На самом деле не хватает информации, чтобы сказать. Несмотря на то, что я не в макушке, я не уверен, какой будет фактический вариант использования для «общего класса, представляющего коллекцию общих объектов». Почему бы просто не использовать коллекции напрямую?

Другие советы

Почти всегда есть способ параметризировать ваш код. Вкратце, я буду набирать userclass, как это:

public UserClass <N extends Number> {
     MyCollection<N> c;

     public method(MyObject<N> o){
          c.foo(o);      
     }
} 

Редактировать
Если вы беспокоитесь о том, чтобы полюбить свой клиент-код с помощью Generics, вы можете сделать абстрактный класс Typed и предоставить непредубированные реализации, например, это:

public abstract UserClass <N extends Number> {
     MyCollection<N> c;

     public method(MyObject<N> o){
          c.foo(o);      
     }
} 

public class DoubleUserClass extends UserClass<Double> {}

Чтобы уменьшить раздувание класса, вы можете поставить безтипные классы внутри базовый класс:

public abstract UserClass <N extends Number> {
     MyCollection<N> c;

     public method(MyObject<N> o){
          c.foo(o);      
     }

     public static class DoubleImpl extends UserClass<Double> {}
     public static class FloatImpl extends UserClass<Float> {}
     public static class IntegerImpl extends UserClass<Integer> {}
} 

И используйте их так: new UserClass.DoubleImpl() так далее

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

Однако, конечно, лучше указать общие, где это возможно. В вашем примере вы можете добавить общий параметр в userclass, как предполагает богемян.

Что касается того, является ли ваша коллекция плохим дизайном: интерфейсы/инфраструктура, которую вы определяете здесь, кажется чрезмерно общей. Что значит MyCollection это нельзя сделать просто с java.util.List<YourClass>? Действительно ли необходимость в MyObject интерфейс? Если вы хотите «пометить» определенный тип классов, наверняка вы можете придумать более конкретное описание того, что отличает эти объекты от любых других Object?

 MyCollection<?> b; 

 public method2(MyObject<?> o){
      b.foo(o); 
 }

Если есть гарантия вне бандита, что b.foo(o) безопасен, тогда нам нужно заставить этот вызов работать. Представить вспомогательный метод

<N extends Number>
void foo(MyCollection<N> collection, MyObject<?> obj)
{
    @SuppressWarnings("unchecked")
    MyObject<N> obj2 = (MyObject<N>)obj;

    collection.foo(obj2);
}

MyCollection<?> b;
void method2(MyObject<?> o){
     foo(b, o); // now works
}

Актерский состав от MyObject<?> к MyObject<N> безопасен из-за внеполосной гарантии. Это проверенный актерский состав в этом смысле, поэтому мы оправданы, чтобы подавить предупреждение.

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

Кастинг с участием дженериков немного сложно; это не интуитивно, как foo(b,o) работает.

Хорошо использовать необработанные типы MyCollection, MyObject Чтобы избежать хлопот. Не обращайте внимания на предупреждение о том, что вы не должны использовать необработанный тип. Это чепуха.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top