Универсальный интерфейс для себя, использовать без предупреждения rawtype

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

//Item is a raw type. References to generic type Item<T> should be parameterized.
public interface Item<T extends Item>
{
    // Item is a raw type. References to generic type Item<T> should be parameterized.
    public static final Item DEFAULT_ITEM = new FooItem(Color.RED);

    // Because using "something = new Item(Default_Item)" won't work.
    public T Copy();

    public void Foo();
    public void Bar();
}

public class RepairMan
{
    // Item is a raw type. References to generic type Item<T> should be parameterized.
    Item itemNeedingRepairs;

    // Item is a raw type. References to generic type Item<T> should be parameterized.
    public RepairMan(final Item item)
    {
        itemNeedingRepairs = item.Copy();
    }       
}

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

Некоторые заметки:

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

Не стесняйтесь изменить название, если есть лучший способ описать эту проблему, я не уверен.

1 ответ

Решение

На каждое предупреждение реагирует по-разному, поэтому требуется и другое лекарство.

1: интерфейс:

public static interface Item<T extends Item> { public T Copy(); }

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

Вы должны были явно попросить, чтобы T был того же типа, что и так:

public static interface Item<T extends Item<T>> {
     public T Copy();
}

2: Элемент по умолчанию:

public static final Item DEFAULT_ITEM = new FooItem(Color.RED);

Проблема с вашим элементом по умолчанию в интерфейсе состоит в том, что, поскольку он является необработанным, он не следует этому ограничению. это copy() Метод может вернуть Item с другим параметром. Если вы хотите применить это к этому элементу, вам нужно объявить его как FooItem следующим образом:

public static final FooItem DEFAULT_ITEM = new FooItem(Color.RED);

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


3: Ремонтник

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

Все ли RepairMen способны починить любой предмет? В этом случае Вы должны выразить это, используя подстановочный знак <?> на всех ваших полях и методах ремонтника.

public static class RepairMan {
    Item<?> itemNeedingRepairs; // Any Item is acceptable
    public RepairMan(final Item<?> item) { // Any Item is acceptable
        itemNeedingRepairs = item.Copy();
    }       
}

Специалисты по ремонту, такие как сантехник и электрик, должны ограничивать типы предметов, которые они могут ремонтировать? В этом случае вы должны позволить RepairMen установить некоторые границы для параметра Item.

public static class RepairMan<T extends Item<T> {
    TitemNeedingRepairs;
    public RepairMan(final Titem) {
        itemNeedingRepairs = item.Copy();
    }       
}

Пример реализации с использованием границ:

public static interface ElectricItem extends Item<ElectricItem>{}

public static class LightBulb implements ElectricItem{
    @Override
    public LightBulb Copy() {
        return new LightBulb();
    }
}

public static class Electrician extends RepairMan<ElectricItem>{
    ElectricItem itemNeedingRepairs; // Only electric Items acceptable
    public Electrician(ElectricItem item) {
        super(item);
    }
}

public static void main(String[] argc){
    LightBulb bulb = new LightBulb();
    new Electrician(bulb);
}

Заключительные слова

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

public void repair(Item<?> item){...}
Другие вопросы по тегам