Шаблон универсального метода в Java - PullRequest
4 голосов
/ 02 февраля 2012

Я очень новичок в дженериках Java и потратил непомерное количество времени в поисках подходящего решения (если есть).

Я пытаюсь разработать адаптеры, которые обрабатывают объекты определенного типа класса. Как описано ниже, класс CAdapter обрабатывает только объекты "CClass". Я пытаюсь предоставить абстрактный универсальный адаптер, который обрабатывает большую часть работы (так же, как коллекции Java, такие как LinkedList). Затем я предоставляю конкретную реализацию адаптера для каждого поддерживаемого типа.

// Classes

public interface AInterface {
  public String toString();
}

public class BClass extends AInterface  {
  public String toString() { return "BClass "; }
}

public class CClass extends AInterface  {
  public String toString() { return "CClass"; }
}

// Adapters

public interface AdapterInterface<T extends AInterface> {
  public T getInterface();
}

public class BAdapter implements AdapterInterface<BClass> {
  private BClass aInterface = null;
  public BClass getInterface() { return aInterface; }
}

public class CAdapter implements AdapterInterface<CClass> {
  private CClass aInterface = null;
  public CClass getInterface() { return aInterface; }
}

Во-первых, я прочитал, что предоставление КОНКРЕТНОЙ реализации для такого универсального адаптера осуждается (что-то о том, что Бог убил котенка)! Может быть, кто-нибудь мог бы расширить это?

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

public <T extends AInterface> AdapterInterface<T> getAdapter(String type) {
  AdapterInterface<T> result = null;
  if (type.equals("C") {
    result = new CAdapter();
  }
  return result;
}

Конечно, компилятор будет жаловаться на несоответствие CAdapter. Учитывая любой тип объекта AInterface, я хотел бы иметь возможность загрузить правильный адаптер и обработать его соответствующим образом. Я не в состоянии понять фабричный образец, чтобы достигнуть этого.

Любые мысли будут с благодарностью.

Ответы [ 2 ]

3 голосов
/ 03 февраля 2012

Мой ответ немного лишний, но:

Что-либо с означает «мой вызывающий знает, что это за тип, но я не знаю».Итак,

AdapterInterface<T> result = null;

Означает «Я на самом деле не знаю, что такое тип результата, это то, что думает мой вызывающий».Компилятор жалуется на это:

result = new CAdapter();

Поскольку этот код не может предполагать, что T является CClass.

На самом деле, есть нет способ сделать этобез приведения (объявление метода wild carded просто означает, что вам нужно привести результат к тому месту, где вы его вызываете).Актеры - это ваш способ сказать компилятору: «Я знаю, что у вас нет возможности узнать, что это такое, это нормально: я знаю. Поверьте мне. Охладите».Да, вы получите предупреждение.И это нормально.

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

3 голосов
/ 02 февраля 2012

Не используйте здесь дженерики, ковариантный (или контравариантный, никогда не может вспомнить, какой именно) тип возвращаемых значений, кажется, делает то, что вы хотите:

interface AdapterInterface {
    public AInterface getInterface();
}

class BAdapter implements AdapterInterface {
    private BClass aInterface = null;

    public BClass getInterface() {
        return aInterface;
    }
}

class CAdapter implements AdapterInterface {
    private CClass aInterface = null;

    public CClass getInterface() {
        return aInterface;
    }
}

public AdapterInterface getAdapter(String type) {
    AdapterInterface result = null;
    if (type.equals("C")) {
        result = new CAdapter();
    }
    return result;
}

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

public
AdapterInterface<? extends AInterface> getAdapter(String type) {
    if (type.equals("C")) {
        return new CAdapter();
    } else {
        // …
    }
}

Причина, по которой ваш оригинальный метод не будет компилироваться, состоит в том, что T - это какой-то определенный неизвестный тип, который расширяет AInterface;это не означает «любой тип, который простирается от AInterface».Статически невозможно доказать, что возвращаемый адаптер является адаптером того типа, который требуется вызывающему абоненту.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...