Chr*_*311 2 java design-patterns casting instanceof
我有一个界面
public interface Details {
// nothing needed until now
}
Run Code Online (Sandbox Code Playgroud)
它在如下类中使用:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
该接口有两个实现
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
}
Run Code Online (Sandbox Code Playgroud)
我有一个模型类,我想在其中使用这些详细信息,具体取决于实例。
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;
}
// ...
Run Code Online (Sandbox Code Playgroud)
在那里我有一些如下操作
// ...
public void setBooleanB(boolean booleanB) {
if (details instanceof DetailB) {
((DetailB) details).setBooleanB(booleanB);
}
}
// ...
Run Code Online (Sandbox Code Playgroud)
我怎样才能避免这种转换和instanceOf的东西?任何设计模式都适用于此吗?
我认为你遇到的问题是设计味道的集合。你已经把自己逼到了墙角,可能没有简单的出路。我不知道这个解决方案是否适合您,但您至少可以考虑一下。
第一个设计味道是您创建了一个实际上不存在的继承关系。简而言之,植根于的层次结构Details违反了里氏替换原则。当一个类声明(确实Model如此)支持该Details接口时,它就声明任何的实现都Details可以。无论程序被赋予 a DetailsA、 aDetailsB还是某个FooDetails尚未发明的类,程序的正确性和行为都不应该改变。
现实情况是,DetailsA和DetailsB并没有实际关系。您可以看到这一点,因为Details它没有方法,因此也可能是Object任何两个类已经继承的方法。
第二种设计味道是“功能羡慕”。看起来 的许多方法Model只是对其底层属性的传递调用details。您可以考虑,而不是仅仅setBooleanB提供Model一个getDetails方法,然后让调用者直接在Details对象上工作。这不会删除instanceof检查或铸造,但会将它们移出此类。
这里的第三件事与前两件事相关。 Model并不取决于Details它的属性类型会告诉您的,而是取决于(至少)DetailsB。如果是这样的话,那么它的属性类型应该这么说。现在,有时您可能需要 aModel和 a DetailsA,有时您需要 aModel和 a 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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,创建两个绑定到不同Details类型的子类,从而可以承诺做正确的事情,而不需要强制转换或instanceof调用。
public class ModelA extends Model<DetailsA> {
public BigDecimal getBetragA() {
return this.getDetails().getBetragA();
}
}
public class ModelB extends Model<DetailsB> {
public boolean getBooleanB() {
return this.getDetails().isBooleanB();
}
public void setBooleanB(boolean boolB) {
this.getDetails().setBooleanB(boolB);
}
}
Run Code Online (Sandbox Code Playgroud)
我不确定这是否能解决您的问题,但这是需要考虑的事情。