java - 避免强制转换和instanceOf

标签 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;
    }
}

该接口(interface)有两个实现

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

最佳答案

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

第一个设计味道是您创建了一个实际上不存在的继承关系。简而言之,层次结构 Root 于 Details违反了Liskov Substitution Principle 。当一个类声称(如Model那样)支持Details时接口(interface),它声称 Details任何实现会做。无论是否给出 DetailsA,程序的正确性和行为都不应该改变。 ,一个DetailsB ,或一些FooDetails甚至还没有被发明的类。

现实是DetailsADetailsB实际上并不相关。您可以看到这一点,因为 Details没有方法,因此也可能是 Object任何两个类已经继承自该类。

第二种设计味道是“功能羡慕”。 Model的方法好像很多只是对其底层 details 的直通调用属性(property)。您可以考虑,而不是 setBooleanBModel只需提供 getDetails方法,然后让调用者直接在 Details 上工作目的。这不会删除 instanceof检查或强制转换,但这会将它们移出此类。

这里的第三件事与前两件事相关。 Model不取决于Details正如其属性类型会告诉您的那样,而是(至少) DetailsB 。如果是这样的话,那么它的属性类型应该这么说。现在,有时您可能需要 ModelDetailsA 有时您需要 ModelDetailsB ,但不能同时。在这种情况下,您可以使用泛型解决该问题。

首先,创建 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;
    }
}

然后,创建两个绑定(bind)到不同 Details 的子类类型,因此可以 promise 做正确的事情,而不需要强制转换或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);
    }
}

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

关于java - 避免强制转换和instanceOf,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32566299/

相关文章:

java - 第一个列表已排序,另一个未排序,这是合并两个列表的更好方法

java - 日志级别的数值有哪些用例?

java - 在 spring 项目中使用 hibernate 工具

c# - 在像 Entity Framework 这样使用 ORM 时如何处理原始的痴迷?

c++ - cocos2d-x:无法从另一个线程加载 Sprite ,任何模式?

c# - 抽象类单例 C#

C++ 通过右引用传递混淆的函数

c# - 转换泛型类型以构建有效的 Linq 表达式

java - 为什么JDK Map.get不支持返回值的类型推断

java - 为什么这个 if 语句也没有按照我想要的方式执行?