让我们想象一下,我想在表格中显示一个库存项目列表(使用
Java).域模型由一个抽象基类StockItem组成,其中包含各种其他类型的库存项. StockItem提供了一个最小的接口(getId()和getDescription())但除此之外,子类可能有很大的变化.
如果我将自己限制在StockItem上定义的方法,我将无法向用户提供足够的详细信息,因此这意味着某些列将引用不适用于某些行的字段(例如,实物商品是可数的,该计数应出现在表中,而预计也出现在表中的服务项目不可数,在这种情况下应显示“N / A”或类似情况.
为了坚持“可数”的例子,在我看来有几个解决方案(但请记住,Countable不会是唯一涉及的接口).
>使可数接口成为基类的一部分,并强制所有内容都是可数的,即使它们不是.这是没有意义的类需要返回一些特殊值或抛出异常或以其他方式表明它们违反了StockItem的合同.
>在我的迭代器中,使用大量的instanceof检查并适当地进行转换.如果我引入StockItem的新子类或以其他方式更改继承树,我将不得不记得更改此代码.
这两个看起来像对我的反模式,我有兴趣听到可能采取的任何更多的优雅方法.我怀疑这没有灵丹妙药,但如果其他语言具有使这种类型的东西更容易的功能,我也有兴趣听到它们(虽然只是出于普遍的兴趣,我不会在任何时候重新实现这个系统不久:)
谢谢,
菲尔
解决方法@H_502_16@
适配器模式
/**
* Adapt the current instance to the type
* denoted by clazz else return null
* ...
*/
public <T> T adapt(Class<T> clazz){
if( clazz.isInstance(this)){
return (T)this;
}
return null;
}
这将由所有子类继承,并允许调用者安全地转换类型.
不要被泛型推迟,只是说我希望这个方法返回一个与clazz参数类型相同的实例.
现在你的表提供者可以实现这样的事情:
public String getColumnText(Object cell,int columnIndex) {
if (cell instanceof StockItem) {
StockItem item = (StockItem) cell;
switch(columnIndex) {
case ID:
return item.getID;
case DESCRIPTION:
return item.getDescription;
case COUNT:
Countable countableItem = item.adapt(Countable.class);
return countableItem == null ? "N/A" : countableItem.getCount();
}
}
return "N/A";
}
/** * Adapt the current instance to the type * denoted by clazz else return null * ... */ public <T> T adapt(Class<T> clazz){ if( clazz.isInstance(this)){ return (T)this; } return null; }
这将由所有子类继承,并允许调用者安全地转换类型.
不要被泛型推迟,只是说我希望这个方法返回一个与clazz参数类型相同的实例.
现在你的表提供者可以实现这样的事情:
public String getColumnText(Object cell,int columnIndex) { if (cell instanceof StockItem) { StockItem item = (StockItem) cell; switch(columnIndex) { case ID: return item.getID; case DESCRIPTION: return item.getDescription; case COUNT: Countable countableItem = item.adapt(Countable.class); return countableItem == null ? "N/A" : countableItem.getCount(); } } return "N/A"; }