我有一个界面
public interface Details {
// nothing needed until now
}
在以下类中使用:
public class Value {
// many fields
private Details details;
public Value(SomeType type) {
switch (type) {
case TYPE_1:
case TYPE_2:
this.details = new DetailsA();
break;
case TYPE_3:
this.details = new DetailsB();
break;
default:
throw new NotImplementedException("not yet implemented");
}
}
public Details getDetails() {
return this.details;
}
}
界面有两个实现
public class DetailsA implements Details {
private BigDecimal betragA;
public DetailsA() {
}
public BigDecimal getBetragA() {
return this.betragA;
}
public void setBetragA(BigDecimal betragA) {
this.betragA = betragA;
}
}
public class DeailsB implements Details {
private BigDecimal betragB;
private boolean booleanB;
public BetragB() {
}
public BigDecimal getBetragB() {
return this.betragB;
}
public void setBetragB(BigDecimal betragB) {
this.betragB = betragB;
}
public boolean isBooleanB() {
return this.booleanB;
}
public void setBooleanB(boolean booleanB) {
this.booleanB = booleanB;
}
// some more fields
}
我有一个模型类,我想根据实例使用这些细节。
public class Model extends AbstractModel {
private Details details;
public void init(StoerungValue stoerung) {
setDetails(stoerung.getSchaden().getDetails());
}
private void setDetails(Details details) {
this.details = details;
}
// ...
在那里我有一些操作,如下面的
// ...
public void setBooleanB(boolean booleanB) {
if (details instanceof DetailB) {
((DetailB) details).setBooleanB(booleanB);
}
}
// ...
如何避免这种转换和instanceOf的东西?这里有任何设计模式适用吗?
答案 0 :(得分:3)
我认为你在这里遇到的问题是设计气味的集合。你把自己画成了一个角落,可能没有一个简单的出路。我不知道这个解决方案是否适合你,但你至少可以考虑这个。
第一个设计气味是您创建了一个实际上不存在的继承关系。简而言之,以Details
为根的层次结构违反了Liskov Substitution Principle。当一个类声明(如Model
所述)支持Details
界面时,它声称 Details
的任何实现都会声明。该程序的正确性和行为不应该改变是否给出了DetailsA
,DetailsB
或某些尚未发明的FooDetails
类。
现实是DetailsA
和DetailsB
实际上并不相关。您可以看到这一点,因为Details
没有方法,因此也可能是任何两个类已经继承的Object
。
第二个设计气味是“特征羡慕”。似乎Model
的许多方法只是对其基础details
属性的传递调用。您可以考虑,而不是让setBooleanB
Model
只提供getDetails
方法,然后让调用者直接在Details
对象上工作。这不会删除instanceof
检查或转换,但会将它们移出此类。
这里的第三件事与前两件有关。 Model
取决于Details
,因为它的属性类型会告诉您,而是取决于(至少)DetailsB
。如果是这种情况,那么它的属性类型应该这样说。现在,有时可能需要Model
DetailsA
而有时你需要Model
{{1}但是,它不能同时 。在这种情况下,您可以使用泛型来解决这个问题。
首先,使DetailsB
类具有通用性,并使用一个类型参数来告知其底层Model
必须实际是什么。
Details
然后,创建两个绑定到不同public abstract class Model<T extends Details> {
private T details;
public void init(T dets) {
setDetails(dets);
}
public void setDetails(T dets) {
this.details = dets;
}
public T getDetails() {
return this.details;
}
}
类型的子类,因此可以保证做正确的事情而不需要强制转换或调用instanceof。
Details
我不确定这是否能解决你的问题,但这是值得考虑的事情。