2015-11-25 3 views
0

Так что у меня локатор сервиса, чтобы найти фабрики (здесь реестра):Построение службы локатора (реестра) для общих заводов

public interface Registry { 
    void addFactory(Factory<? extends Component> factory); 
    Factory<? extends Component> getFactory(String name); 
} 

И фабричные:

public interface Factory<C extends Component> { 
    C createComponent(); 
    void render(C); 
} 

и использовать их таким образом, :

Registry registry; 
public <X extends Component> void createIt(String name) { 
    Factory<X> factory = (Factory<X>)registry.getFactory(name); //<- I need to cast this 
    X component = factory.createComponent(); 
    //..do something to component as it's a Component 
    factory.render(component) 
} 

Я не смог найти способ захватить этот общий метод. Информация должна быть там, чтобы знать, что все, что завод возвращает (X), может быть возвращено на завод, не зная, что это такое. Я пробовал много разных подходов без каких-либо успехов, рано или поздно получаю предупреждение.

Edit:

Вот пример того, как заводы выглядеть так:

public class SimpleFactory implements Factory<SimpleComponent> { 
    public SimpleComponent createComponent() { 
    return new SimpleComponent(); 
    } 
    public render(SimpleComponent sc) { 
    sc.doInThisSC(); 
    } 
} 

второй завод может выглядеть следующим образом:

public class ComplexFactory implements Factory<ComplexComponent> { 
    public ComplexComponentcreateComponent() { 
    return new ComplexComponent(); 
    } 
    public render(ComplexComponent cc) { 
    cc.doInThisCC(); 
    } 
} 

Я пытаюсь выразить, что factory.render(factory.createComponent()) должен всегда работать независимо от того, что я могу сделать с любой фабрикой, полученной из реестра.

+0

'(Factory ) registry.getFactory (имя); 'всегда будет давать непроверенное предупреждение – Ramanlfc

+0

@Ramanlfc да, вопрос в том, могу ли я изменить подписи, так что мне не нужно его бросать. – estani

ответ

0

Предполагая, что вы используете только методы, определенные на компонент, вы можете сделать:

Registry registry; 
public <X extends Report> void createIt(String name){ 
    Factory<Component> factory = registry.getFactory(name); 
    Component component = factory.createComponent(); 
    // ... 
    factory.render(component); 
} 

Хитрость заключается в том, что вы должны работать с общим знаменателем всех различных генериков. Когда у вас есть общий тип F extends Foobar, F предоставляется вам как тип Foobar, хотя вы можете его переделать. Ваши подписи Registry и Factory определяют себя как совместимые с Component, но это означает, что все, что они могут предположить, что они получают, это Component, и это все, что вы видите без кастинга.

Если вам нужны дополнительные методы, которые не определены как часть Component, то вы можете создать интерфейс, который расширяет интерфейс Component (при условии, Component является интерфейсом):

public interface X extends Component{ 
    // Additional methods that will be required in addition to those 
    // required by Component 
} 

Вы можете объявить дженерики как расширение X и все эти методы доступны вам.

редактировать:

Вы также могли бы быть Factory родительский класс без родового тега, то есть подтипы обрабатывать полиморфизм для вас. Каждый подтип мог тогда знать логику вашей программы, что она имеет дело с чем-то, что он создал, и инкапсулировать отливку сами по себе что-то, что чувствует себя чище:

public class X implements Component{ 
    // ... 
} 

public class XFactory extends Factory{ 
    @Override 
    public Component createComponent(){ 
     return new X(); 
    } 

    @Override 
    public void render(Component in){ 
     // We know it's an X so we can cast it here: 
     X real = (X)in; 
     // ... 
    } 
} 
+0

Это не работает, 'завод.render' не принимает 'Компонент', он просто принимает' C', который уже определен как нечто, расширяющее 'Component'. Это действительно важно, поскольку только фабрика знает, как обращаться с этим типом Компонента. (Обратите внимание, что у меня была опечатка, где сказано, что сообщение должно иметь указанный компонент) – estani

+0

'Компонент' расширяет' Компонент' по определению; Я думаю, что не понимаю, что вы пытаетесь сделать здесь. Пока вы не используете что-то конкретное для обработки разных типов «Компонента» по-другому, это прекрасно. Если вы и не хотите делать кастинг, перейдите к предложению интерфейса оболочки. Если вы хотите программным образом обрабатывать типы компонентов, для этого используется кастинг. Вы также можете сделать несколько подписей для каждого конкретного подкласса, который вы хотите обработать. –

+0

У вас также могут быть определенные подклассы Factory, которые обрабатывают полиморфизм для вас вместо использования синтаксиса generic, тогда фабрика всегда может знать, что она возвращает тип, который он создал. Это, вероятно, все еще будет включать в себя литье внутри фабрики, но оно становится чище. Когда вы начинаете немного усложняться, вам иногда просто нужно делать кастинг; Java дает вам это как инструмент по какой-то причине. –

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