【问题标题】:how the instanceof usage can be avoided?如何避免使用instanceof?
【发布时间】:2017-11-02 18:15:29
【问题描述】:

我们如何避免使用instanceof 操作符来编写干净的代码 比如说: 如果一个对象是 Type1 做某事,但如果它是 Type2 则做其他事情。

if(obj instanceof T1){
    doSomething()
 }else(obj instanceof T2){
    doOtherThing()
 }

【问题讨论】:

  • 你知道是instanceof,而不是instanceOf?您可以实现Chain of responsibility,其中链中的每个元素都执行一个instanceof 操作并在合适的情况下使用该事件。也许您应该更详细地解释您要完成的工作,因为这似乎是XY problem
  • 这实际上取决于代码在做什么,您可以控制哪些类(与您无法抽象出接口的第三方库相反)等。不幸的是,问题是它的立场太宽泛了。答案通常会使用覆盖的方法,但具体情况各不相同。
  • 我个人更喜欢getClass() 方法,说我正在实现的逻辑需要知道确切的类而不是任何超类
  • 使用instanceOf 简单易读也不错。如果你想隐藏它并以更动态的方式使用,你可以使用visitor pattern
  • @Turing85:这个问题被问到是为了理解 instanceof 操作符链是如何被认为是代码异味。

标签: java instanceof


【解决方案1】:

通常,您使用一系列 instanceof 和一个强制转换来调用存在于一个类中但不存在于其他类中的特定方法:

if(obj instanceof T1){
    ((T1)obj) doSomething();
}
else(obj instanceof T2){
    ((T2)obj) doOtherThing();
}

为避免这种情况,如果您可以修改这些类,T1T2 应该是公共基类的子类,并且调用的方法应该在基类中定义。
这样,每个子类都可以实现它,你可以这样写:

obj.doSomething();

如果您无法修改这些类,您始终可以引入一个 Adapter 类来包装它们,以提供调用这些方法的通用方式。

适配器

public interface Adapter{
    void process();
}

AdapterForT1

public class AdapterForT1 implements MyAdapter{

    private T1 adapted;
    public AdapterForT1(T1 adapted){
      this.adapted = adapted;
    } 

    public void process(){
       adapted.doSomething();
    }

}

AdapterForT2

public class AdapterForT2 implements MyAdapter{

    private T2 adapted;
    public AdapterForT2(T2 adapted){
      this.adapted = adapted;
    } 

    public void process(){
       adapted.doOtherThing();
    }

}

你可以这样使用它们:

MyAdapter adapter = new AdapterForT1(obj);
...
adapter.process();

或:

MyAdapter adapter = new AdapterForT2(obj);
...
adapter.process();

【讨论】:

    【解决方案2】:

    创建两个类都实现的interface。接口是一种契约,每个实现类都必须遵守。

    这样,您可以确保此类的每个实例都实现了该接口中定义的所有方法。

    例如:

    public interface CustomExecutable {
        void execute();
    }
    

    那么你的两个班级:

    public class T1 implements CustomExecutable {
        @Override
        public void execute() {
            // Do t1 logic
        }
    }
    
    public class T2 implements CustomExecutable {
        @Override
        public void execute() {
            // Do t2 logic
        }
    }
    

    在您的主程序中,您可以执行以下操作:

    CustomExecutable ce = new T1();
    ce.execute(); // Does t1 logic
    ce = new T2();
    ce.execute(); // Does t2 logic
    

    instanceof 不再是必需的,因为每种类型都有自己的execute 编码方式。

    【讨论】:

      【解决方案3】:

      您需要在此处使用方法覆盖,然后从不同类的不同实例调用相同的函数,这些实例将根据各个类中的实现执行不同的指令集

      例如,你有一个类 T,然后类 T1 和类 T2 都扩展了类 T,并且所有三个类都实现了 executeTask 函数

      所以,

      T t1 = new T1();
      T t2 = new T2();
      
      // this will execute function overridden in T1
      t1.executeTask();
      
      // this will execute function overridden in T2
      t2.executeTask();
      

      【讨论】:

        猜你喜欢
        • 2012-04-18
        • 2022-11-15
        • 1970-01-01
        • 2012-08-13
        • 2011-09-03
        • 2013-03-05
        • 2020-08-30
        • 2019-10-12
        • 1970-01-01
        相关资源
        最近更新 更多