2012-02-02 3 views
4

Я очень новичок в Java-генераторах и потратил непомерное количество времени на поиск подходящего решения (если оно есть).Шаблон общих методов в 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 я хотел бы иметь возможность загрузить правильный адаптер и обработать его соответствующим образом. Я не понимаю, что такое фабрика, чтобы добиться этого.

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

+0

Вы вызываете foo. getAdapter (C)? В противном случае T несвязано. Более распространенным шаблоном будет публикация AdapterInterface getAdapter (класс clazz); – Nialscorva

+0

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

+0

@Nialscorva Это не имеет большого значения. Система типов не может доказать ограничение, предоставляете ли вы токен типа или нет. Символы типа полезны, когда подпись метода похожа на ' T getWhateverOfType (класс )' из-за 'Class.newInstance()', 'Class.cast()' et al. Они не полезны, если вы не имеете дело с экземплярами данного класса. – millimoose

ответ

3

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

Все с <T> означает «мой абонент знает, что этот тип, но я не». Так

AdapterInterface<T> result = null; 

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

result = new CAdapter(); 

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

Фактически, есть no способ сделать это без приведения (объявление метода дикой картой означает, что вам нужно указать результат, когда вы его назовете). Бросок - это ваш способ сказать компилятору: «Я знаю, что у вас нет способа узнать, что это такое, все в порядке: я знаю. Поверь мне, Чил». Да, вы получите предупреждение. И все в порядке.

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

+0

Спасибо за ваш ответ. Я ценю, что это было очень ясно объяснено. –

+0

Я краду фразы: «Мой звонящий знает, что это за тип, но я этого не делаю», это делает вещи намного яснее, чем то, как я это объясняю. – millimoose

3

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

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; 
} 

Если нет некоторые другие методы в интерфейсах вы Ждут» t упоминание. Ниже также компилируется классы является родовым:

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

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

+0

Спасибо за ваш вклад. Между вашим ответом и тем, что ниже (PaulMurrayCbr), я думаю, что, наконец, понял, как обращаться с обработкой Java-дженериков, особенно при использовании шаблона фабричного дизайна. Я просто выполнил бы один акт на заводе и подавил бы предупреждение, понимая, что дженерики (по крайней мере, с Java 5/6) не могут устранить все кастинга. –

+0

@MichaelCronk Правильно. Многие вопросы SO на основе дженериков Java на самом деле имеют тенденцию быть ОП, спрашивая, как реализовать ограничение типа, о котором он думает, только чтобы выяснить, почему это невозможно. Однако вы можете и должны стараться избегать непроверенных бросков (приведение типов к параметрам и параметризованным типам) в максимально возможной степени, заменив их «Class.cast()» и другими проверками типа времени выполнения. Или инкапсулируйте их как можно ближе в код, который, как вы знаете, правильный, даже если система типа не может его проверить. – millimoose

Смежные вопросы