避免在基于工厂的通用MVP框架中进行强制转换

时间:2018-08-29 17:07:35

标签: java generics mvp software-design

我正试图实现一种将MVP模式中的View和Presenter分离的方法,以提供一个框架,该框架正是这样做的,但是在之后我感到困惑。

背景

对于连接的演示者,我有一个具有通用类型的View界面,反之亦然。这些接口将由实施开发人员扩展。具体接口对此问题不感兴趣,但是它们的类定义都如下所示:

public interface Presenter<T extends View>

public interface View<T extends Presenter>

想法是视图和演示者都知道相反的界面。

对于使用此结构,开发人员应提供一个工厂,该工厂可实例化要显示的View和正在处理此View的Presenter。他将它们都交给了一个名为SuperController的类。它们由视图的类关联。

创建Presenter的PresenterFactory接口没有参数,并返回Presenter实现,并显示以下内容:

public interface PresenterFactory<T extends View> {

    <S extends Presenter<T>> S create();

}

用于创建View的ViewFactory接口,基于Presenter创建一个View实现,并显示以下内容:

public interface ViewFactory<T extends View, S extends Presenter<T>> {

    T create(S presenter);

}

问题

我遇到的问题如下:

我想提供一个带有TestView和TestPresenter的示例。看起来像这样:

public interface TestPresenter extends Presenter<TestView> {...}

public interface TestView extends View<TestPresenter> {...}

还提供了一个ViewFactory,它看起来像这样:

class TestViewFactory implements ViewFactory<TestView, TestPresenter> {

    @Override
    public TestView create(TestPresenter presenter) {
        return new TestViewImpl(presenter);
    }
}

这是TestPresenterFactory:

private class TestPresenterFactory implements PresenterFactory<TestView> {

    @Override
    public <S extends Presenter<TestView>> S create() {
        return new TestPresenterImpl();
    }
}

该代码无法进行编译。问题是TestPresenterFactory的返回值。 Java说,它期望S而不是TestPresenterImpl。此外,强制转换为TestPresenter也不起作用。但是,强制转换为S 将有效。它可以编译并且也可以成功运行,但这不是我想要实现的开发人员要做的。

为什么存在此问题?为何无法投射到具体界面?在我看来,这应该可行,因为TestPresenterImpl实现了TestPresenter,它扩展了通用类型TestView的Presenter,但它不可编译。


以下有用。如果您像这样更改PresenterFactory定义:

public interface PresenterFactory<T extends View, S extends Presenter<T>> {

    S create();

}

示例实现现在看起来像这样:

private class TestPresenterFactory implements PresenterFactory<TestView, TestPresenter> {

    @Override
    public TestPresenter create() {
        return new TestPresenterImpl();
    }
}

它可以编译并运行,就像在上面的示例中我强制转换为S一样。

但是,这不是我想要的。通用类型声明是多余的。让实施开发人员声明View 演示者,以便仅创建演示者看起来很尴尬。如果可以在方法中推断出类型,那将真的很棒。

此外,我不想强​​迫实施者将其强制转换为S。

有没有更优雅的方式呢?


修改

一个问题重复出现,我想与this question保持距离。

由此产生的问题与生产者扩展超级消费者无关。我有两个生产商(工厂)在使用。两者都产生一个类。一个依赖于另一个类(视图依赖于Presenter),而另一个则不依赖(可以使用默认构造函数实例化Presenter)。所有受尊重的接口都具有T扩展XYZ定义,以允许生成继承该接口(Presenter或View)的接口。

这里的真正问题是ViewFactory中的泛型可以由Java推断。这两个泛型类型都在类定义中声明。在PresenterFactory中,Java无法推断方法级别的泛型。即使通用类型与视图工厂<S extends Presenter<T>>中的类型相同;在此方法中,无法推断出这种类型。

解决方案是强制转换(我不希望使用开发人员执行此操作)或在类定义中声明PresenterType(这似乎是多余的。唯一感兴趣的是,已定义视图)并返回该视图的所有Presenter。)

我的问题是,我应该怎么做才能解决由extends子句引起的上述问题?

1 个答案:

答案 0 :(得分:1)

对于初学者来说,这将解决问题:

interface PresenterFactory<T extends View, S extends Presenter<T>> {
    S create();
}

class TestPresenterFactory implements PresenterFactory<TestView, TestPresenterImpl> {

    @Override
    public TestPresenterImpl create() {
        return new TestPresenterImpl();
    }
}

但是我还是不喜欢:

  • View和Presenter之间的循环依赖性;
  • 原始类型的使用:实际上,如果您在各自的接口声明中盲目使用View<?>Presenter<?>,那么它将再次无法编译(TestPresenterFactory将失败)。 / li>

--- 编辑 ---

那么如何解决最后2点以及原始问题:

interface Presenter<P extends Presenter<P, V>, V extends View<P, V>> {

}

interface View<P extends Presenter<P, V>, V extends View<P, V>> {

}

interface PresenterFactory<P extends Presenter<P, V>, V extends View<P, V>> {

    P create();

}

interface ViewFactory<P extends Presenter<P, V>, V extends View<P, V>> {

    V create(P presenter);

}

interface TestPresenter extends Presenter<TestPresenter, TestView> {}

class TestPresenterImpl implements TestPresenter {

}

interface TestView extends View<TestPresenter, TestView> {}

class TestViewImpl implements TestView {

    public TestViewImpl(Presenter<?, ?> presenter) {
    }
}

class TestViewFactory implements ViewFactory<TestPresenter, TestView> {

    @Override
    public TestView create(TestPresenter presenter) {
        return new TestViewImpl(presenter);
    }
}

class TestPresenterFactory implements PresenterFactory<TestPresenter, TestView> {

    @Override
    public TestPresenter create() {
        return new TestPresenterImpl();
    }
}