避免使用cast和instanceOf

时间:2015-09-14 13:37:22

标签: java design-patterns casting instanceof

我有一个界面

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的东西?这里有任何设计模式适用吗?

1 个答案:

答案 0 :(得分:3)

我认为你在这里遇到的问题是设计气味的集合。你把自己画成了一个角落,可能没有一个简单的出路。我不知道这个解决方案是否适合你,但你至少可以考虑这个。

第一个设计气味是您创建了一个实际上不存在的继承关系。简而言之,以Details为根的层次结构违反了Liskov Substitution Principle。当一个类声明(如Model所述)支持Details界面时,它声称​​ Details的任何实现都会声明。该程序的正确性和行为不应该改变是否给出了DetailsADetailsB或某些尚未发明的FooDetails类。

现实是DetailsADetailsB实际上并不相关。您可以看到这一点,因为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

我不确定这是否能解决你的问题,但这是值得考虑的事情。