我有以下两个接口:
/**
* A marker interface to denote that an object implements a view on some other object.
*
* @param <T> The type of object that is viewed
*/
public interface View<T extends Viewable<View<T>>> {
}
/**
* An interface for objects that are viewable via a view.
*
* @param <T> The type of viewable object
*/
public interface Viewable<T extends View<?>> {
public void addViewCallback(final T view);
public void removeViewCallback(final T view);
}
我想强制执行以下操作:
View
的类型参数(称为(a))应该是Viewable
,可以查看该视图(a)。Viewable
的类型参数(称为(b))应为View
,可通过相同的可见(b)查看。我认为我完成了View
的界限,但是我如何让它们为Viewable
工作呢?我现在得到的是编译,但没有提供足够的保护。
我现在不能制定一些我不想要的东西,但是我可以制定我做想要的东西,如果有帮助的话:
public class Hand implements Viewable<HandView>
public interface HandView extends View<Hand>
答案 0 :(得分:7)
由于您的View
是一个标记界面,而且您现在还没有制定任何被接受的内容,而您不要想要,我完全质疑View
接口的使用。你对自己施加了不必要的限制,只能带来麻烦。
/**
* An interface for objects that are viewable via a view.
*
* @param <T> The type of viewable object
*/
public interface Viewable<T> {
public void addViewCallback(final T view);
public void removeViewCallback(final T view);
}
答案 1 :(得分:5)
正如@SimonAndréForsberg所讨论的那样,编程过于防守往往是不必要的浪费时间,我们应该相信我们自己的声明。
但是,为了它的乐趣,这里有一个解决方案,可以在编译时强制执行对类/接口声明的所有限制。
View
界面:public interface View<T extends Viewable<T, ?>> {}
在这里,我们只想确保类型参数为Viewable
。
第二种类型参数不需要限制,因为如果Viewable
本身不是Viewable<T,?>
,?
的声明将不允许View<T>
存在}。
Viewable
界面:public interface Viewable<T extends Viewable<T,?>, V extends View<T>> {
public void addViewCallback(final V view);
public void removeViewCallback(final V view);
}
T
需要声明为Viewable
,因为我们将其用作行末View<T>
的类型参数。?
不需要限制,因为我们之后说如果第一个类型参数是View<T>
,则第二个类型参数必须是T
。public class Hand implements Viewable<Hand, HandView> {
@Override
public void addViewCallback(HandView view) {}
@Override
public void removeViewCallback(HandView view) {}
}
public interface HandView extends View<Hand> {
}
答案 2 :(得分:3)
我设法让它工作,同时考虑所有其他答案。
似乎@Joffrey's answer让我开始了很多,但后来我意识到这种方式根本不可能,因为方法参数不能协变。
我也同意这可能是太多的工作,但这就是为什么它是一些实验性的东西,在工作时间压力我可能会在浪费时间之前三思而后行。
可能的解决方案之一是:
/**
* A marker interface to denote that an object implements a view on some other object.
*
* @param <T> The type of object that is viewed
*/
public interface View<T extends Viewable<T, ? extends View<T>>> {
}
/**
* An interface for objects that are viewable via a view.
*
* @param <T> The type of viewable object
* @param <V> The concrete view on the viewable object
*/
public interface Viewable<T extends Viewable<T, V>, V extends View<T>> {
public void addViewCallback(final V view);
public void removeViewCallback(final V view);
}
示例实施:
public interface HandView extends View<Hand> {
public void onCardAdded(final Card card);
public void onCardPlayed(final int cardIndex);
public void onCardsSwapped(final int cardIndexOne, final int cardIndexTwo);
}
public class Hand extends AbstractCollection<Card> implements Collection<Card>, Viewable<Hand, HandView> {
private final List<HandView> views = new ArrayList<>();
//...
@Override
public void addViewCallback(final HandView view) {
views.add(Objects.requireNonNull(view));
}
@Override
public void removeViewCallback(final HandView view) {
views.remove(Objects.requireNonNull(view));
}
@Override
public boolean add(final Card card) {
Objects.requireNonNull(card);
States.requireFalse(isFull(), "hand is full");
list.add(card);
views.forEach(view -> view.onCardAdded(card));
return true;
}
//...
}
答案 3 :(得分:2)
这对我有用的唯一方法是指定View和Viewable类型参数:
public interface View<VB extends Viewable<VB,T>, T extends View<VB,T>>
public interface Viewable<VB extends Viewable<VB,T>, T extends View<VB,T>>
请记住,这需要您创建特定的界面:
public interface Hand implements Viewable<Hand,HandView>
public interface HandView extends View<Hand,HandView>