Java Factory在传递的类型上创建Generic参数化

时间:2016-06-23 10:34:59

标签: java generics factory

我有宿醉,今天我特别慢。

我想将Intent的子类传递给某个工厂,并返回Handler<? extends Intent>,其中参数化类型与传递给工厂的参数类型匹配。

public interface HandlerFactory
{
    <I extends Intent> Handler<I> build(I intent);
}

我正在努力实现这个目标。我不想要一个大讨厌的if / else检查所有不同类型的Intent,然后为每个Handler<>创建适当的Intent,并根据我们结束的条件块进行投射我不想使用访问者模式的某些变体,因为我的工厂变得耦合到 Handler<? extends Intent> / OrgHandler的每个子类。更多可插拔的东西&#39;似乎很可取。

如何在没有肮脏的铸造的情况下实现这一点?下面简化的情况不会编译,因为虽然Handler<OrgIntent>实现了Intent,但编译器不会知道 I已通过({{ 1}})是OrgIntent而不是任何其他子类。

public class SimpleHandlerFactory implements HandlerFactory
{    
    @Override
    public <I extends Intent> Handler<I> build(I intent)
    {
        // Filthy conditional that I want to avoid
        if(intent instanceof OrgIntent)
        {
            // Cast seems wrong
            return (Handler<I>) new SimpleOrgHandler(intent);
        }
        else if(intent instanceof SomeOtherIntent)
        {
            ...
    }
}

更新

客户端代码有List<Intent>并且并不真正关心子类型;它需要构建一个List<Handler>(我想我需要在那里进行原始类型抑制),然后在每个上面调用一个方法。

List<Intent> intents = orderedIntentBuilder.getOrderedIntents(declaration);
for(Intent intent : intents)
{
    Handler<Intent> handler = handlerFactory.build(intent);
    handler.resolve(someUnimportantArg);
}

3 个答案:

答案 0 :(得分:2)

我在这里看到了循环依赖的可能性。您希望从Intent转到HandlerIntent不应该知道Handler,而Handler已经了解Intent

有人也可能想知道为什么一个类需要一个专用的处理程序,那么部分类本身的处理程序功能不应该呢?

任何方式,一种简单的方法是向getHandler添加Intent方法:

interface Handler<T extends Intent> {}

interface Intent {
    Handler<?> getHandler();
}

class OrgIntent {    
    @Override
    public Handler<OrgIntent> getHandler() {
        return new SimpleOrgHandler(this);
     }
}

...
List<Intent> intents = orderedIntentBuilder.getOrderedIntents(declaration);
for(Intent intent : intents)
{
    Handler<?> handler = intent.getHandler();
    handler.resolve(someUnimportantArg);
}

这会在IntentHandler之间创建循环依赖关系。您可以使用哪种方法,但也有办法解决这个问题。

通过提取处理程序的数据“模型”,进入第三类:

interface IntentModel {...}

Handler现在可以在此模型上运行,而不是Intent本身。

class OrgIntent {    
    @Override
    public Handler<OrgIntentModel> getHandler() { // <-- Handler<OrgIntentModel>
        return new SimpleOrgHandler(this.model); // passing only model
    }
}

创建依赖项:

Intent -> IntentModel
Intent -> Handler
Handler -> IntentModel

在这种情况下,您可能希望将Handler功能与IntentModel合并。那里没有循环依赖,因为模型只能自行运行。

答案 1 :(得分:1)

您可以将参数化类型添加到工厂类:

public interface HandlerFactory<I extends Intent> {
    Handler<I> build(I intent);
}

和您的SimpleHandlerFactory

public class SimpleHandlerFactory implements HandlerFactory<OrgIntent> {    
    @Override
    public Handler<OrgIntent> build(OrgIntent intent) {
        return new SimpleOrgHandler(intent);
    }
}

答案 2 :(得分:1)

  

实际上,Intent类只是数据,而Handler类的基本原理是我想为库的用户提供不同的方法来实现对这些数据起作用的行为。

所以这是我的另一个想法。

您可以在模糊意图类型之前实例化该功能,这是一个粗略的例子:

  • 在此,SomeInputType将是您派生的类型 意图的数据。

  • Intent类型已重命名为IntentModel(因为它只是一个 数据类)。

  • 类型Handler已重命名为Intent(因为这是其中之一 真正的功能是)。

class OrgIntentModel implements IntentModel {
    public OrgIntentModel(SomeInputType input) {...}
}

// Abstract factory pattern
interface IntentFactory {
    // Constructs an Intent with custom behaviour.
    // Using the data in the specific model.
    Intent getOrgIntent(OrgIntentModel model);

    // Getters for each model type
}

// This class is implemented by the user.
// You could provide a 'DefaultFactory' as a template to extend.
class UserProvidedFactory implements IntentFactory {...}

class IntentBuilder { // i.e. IntentDeserializer

    private Map<String, Function<? super SomeInputType, ? extends Intent>> map;

    public IntentBuilder(IntentFactory factory) {
        map.put("OrgIntent", makeFunc(OrgIntentModel::new, factory::getOrgIntent));
        // other mappings...
    }

    // Helper method, to help with casting the method references.
    // 'U' represents the specific IntentModel.
    // SomeInputType -> IntentModel -> Intent
    private static <T, U, R> Function<T, R> makeFunc(
        Function<T, ? extends U> f1,
        Function<? super U, R> f2) {
        return f1.andThen(f2);
    }

    public Intent getIntent(SomeInputType input) {
        String intentType = input.getIntentType();
        return map.get(intentType).apply(input);
    }
}