Tho*_*uck 7 java generics mvp software-design
我试图在MVP模式中实现一种将View和Presenter分离的方法,以提供一个框架,这正是这样做的,但在一点之后我感到困惑.
我有一个View接口,其中包含连接的演示者的泛型类型,反之亦然.这些接口将由实现开发人员扩展.具体的界面对这个问题不感兴趣,但这些界面的类定义如下所示:
public interface Presenter<T extends View>
Run Code Online (Sandbox Code Playgroud)
和
public interface View<T extends Presenter>
Run Code Online (Sandbox Code Playgroud)
这个想法是View和Presenter都知道对立的界面.
对于使用此结构,开发人员应提供工厂,实例化他想要显示的视图和处理此视图的Presenter.他把它们都给了一个名为SuperController的类.它们与View的类相关联.
创建Presenter的PresenterFactory接口没有参数,并返回Presenter实现,并查看以下内容:
public interface PresenterFactory<T extends View> {
<S extends Presenter<T>> S create();
}
Run Code Online (Sandbox Code Playgroud)
创建View的ViewFactory接口基于Presenter创建View实现,并查看以下内容:
public interface ViewFactory<T extends View, S extends Presenter<T>> {
T create(S presenter);
}
Run Code Online (Sandbox Code Playgroud)
我遇到的问题如下:
我想提供一个TestView和TestPresenter的示例.那些看起来像这样:
public interface TestPresenter extends Presenter<TestView> {...}
public interface TestView extends View<TestPresenter> {...}
Run Code Online (Sandbox Code Playgroud)
此外,还提供了ViewFactory,如下所示:
class TestViewFactory implements ViewFactory<TestView, TestPresenter> {
@Override
public TestView create(TestPresenter presenter) {
return new TestViewImpl(presenter);
}
}
Run Code Online (Sandbox Code Playgroud)
这是TestPresenterFactory:
private class TestPresenterFactory implements PresenterFactory<TestView> {
@Override
public <S extends Presenter<TestView>> S create() {
return new TestPresenterImpl();
}
}
Run Code Online (Sandbox Code Playgroud)
此代码无法编译.问题是TestPresenterFactory的返回值.Java说,它期望S而不是TestPresenterImpl.此外,转换为TestPresenter将无法正常工作.然而,施放到S 将起作用.它可以编译并运行成功,但这不是我希望实现开发人员做的事情.
为什么会出现这个问题?为什么铸造到具体界面不起作用?在我看来,这应该工作,因为TestPresenterImpl实现了TestPresenter,它扩展了通用类型TestView的Presenter,但它不可编译.
下面做工作.如果您更改PresenterFactory定义,如下所示:
public interface PresenterFactory<T extends View, S extends Presenter<T>> {
S create();
}
Run Code Online (Sandbox Code Playgroud)
示例实现现在看起来像这样:
private class TestPresenterFactory implements PresenterFactory<TestView, TestPresenter> {
@Override
public TestPresenter create() {
return new TestPresenterImpl();
}
}
Run Code Online (Sandbox Code Playgroud)
它可以编译和运行,就像我在上面的例子中转换为S一样.
但是,这不是我想要的.泛型类型声明是多余的.让实现开发人员声明View 和演示者,仅创建Presenter看起来很尴尬.如果类型可以在该方法中推断,那将是非常好的.
另外,我不想强制实现开发人员强制转换为S.
这有更优雅的方式吗?
编辑
提出一个问题作为重复,我想与这个问题保持距离.
由此产生的问题与Producer Extends Consumer Super无关.我有两个生产商(工厂)在使用.这两个都产生了一个类.一个依赖于另一个类(View依赖于Presenter),而另一个依赖于Presenter(Presenter可以使用默认构造函数实例化).所有受尊重的接口都具有T扩展XYZ定义,以允许生成继承该接口的接口(Presenter或View).
这里真正的问题是ViewFactory中的泛型可以由Java推断.两个泛型类型都在类定义中声明.在PresenterFactory中,Java无法推断出方法级泛型.尽管如此,泛型类型与视图工厂中的类型相同<S extends Presenter<T>>; 在该方法中,不能推断出这种类型.
解决方案是要么强制转换(我不希望使用开发人员这样做),要么在类定义中声明PresenterType(这似乎是多余的.唯一感兴趣的是,视图是定义的,任何Presenter为该视图返回).
我的问题是我可以做些什么来解决由extends子句引起的所述问题?
对于初学者来说,这将解决问题:
interface PresenterFactory<T extends View, S extends Presenter<T>> {
S create();
}
class TestPresenterFactory implements PresenterFactory<TestView, TestPresenterImpl> {
@Override
public TestPresenterImpl create() {
return new TestPresenterImpl();
}
}
Run Code Online (Sandbox Code Playgroud)
但我还是不喜欢:
View<?>and Presenter<?>,那么它又不会编译(TestPresenterFactory将会失败)。- -编辑- -
那么,如何解决最后两点以及您原来的问题:
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();
}
}
Run Code Online (Sandbox Code Playgroud)