【问题标题】:Check if Calling Object is Instance of Child Class检查调用对象是否是子类的实例
【发布时间】:2011-07-22 20:01:04
【问题描述】:

我有 2 节课。我们称它们为 A 类和 B 类。A 类包含一个执行某些操作的方法。 B 类用它自己的版本覆盖此方法,但确实在 A 类中对该方法进行了super 调用以执行操作。现在,这工作正常。但是,A 类中的某些动作只有在对象是 A 类的一个实例时才应该执行。换句话说,如果对象是A 类的子实例。

目前,我正在使用instanceof 来检查每个子类,但我需要指定每个子类,因此如果以后添加了新子类,则需要更新此方法。我想要的是一种确定对象是否是子类的动态方法。

有什么好的选择吗,或者instanceof 是要走的路吗?

public class A{

    public void someMethod(){

        // Only perform these actions if it is not a child class.  This is what
        // I am looking for a better solution for
        if(!(this instanceof B)){
            // Some action...
        }

        // Actions to execute for every call
    }
}

public class B extends A{

   @Override
   public void someMethod(){

       super.someMethod();

       // More actions
   }
}

作为对设计的解释,我使用它来生成 XML。在程序中,我有一个List<A> 来存储数据。当需要输出 XML 时,我会遍历列表并调用 generateXMLsomeMethod 在我的示例中代替它的位置)。

创建A类的对象时,需要将其数据包含在<A></A>标签内。创建 B 类对象时,需要将其数据包含在 <B></B> 标记中。但是A 的所有属性也必须在<B></B> 标记内,所以现在它调用相同的generateXML 方法,当对象仅属于A 类时使用。

但正如其他一些人指出的那样,调用相同的方法并不是要走的路。 B 类应该调用 A 类中的受保护方法,该方法只生成必要的信息。

【问题讨论】:

    标签: java oop inheritance polymorphism


    【解决方案1】:

    创建执行特定于类的事情的受保护方法,并从 someMethod() 调用它们。 A 类将提供它的实现,如果子类需要有效地删除该代码,那么它可以用一个空实现覆盖受保护的方法。

    不要与多态作斗争;充分利用它。

    例子:

    public class A {
        protected void someOtherMethod() {
            // Do stuff specific to A here.
        }
    
        public void someMethod() {
            // Do some stuff
    
            someOtherMethod();
    
            // Do some more stuff
        }
    }
    
    public class B extends A {
        @Override
        protected void someOtherMethod() {
            // Empty implementation; B doesn't need to do this.
            // Or do stuff specific to B...
        }
    }
    

    【讨论】:

    • 对,这个方法更有意义。尽管我用更多信息更新了我的帖子,但这个想法仍然适用。谢谢!
    【解决方案2】:

    现在这是一个可怕的设计,应该以不同的方式解决(例如,使从子类调用的部分成为自己的受保护方法),但是如果你真的需要它,你可以检查

    this.getClass() == A.class 查看类是否真的相同。

    【讨论】:

    • 我想给 +1,但我不可能鼓励 OP 糟糕的设计。它确实需要返工。
    • 是的,这确实是一个丑陋的 hack(就像大多数情况下的 instanceof 一样),并且大多数情况下很容易以不同的方式解决。如果他只能控制父类而不是子类(但即便如此,那也是人为的),那么唯一真正的借口就是作为 backcomp hack。
    • 好吧,提到向后兼容你会得到 +1!
    • 我个人希望 cdhowie 的回答“获胜”——否则我会感觉非常糟糕:x
    • 我什至没有想过使用不同的方法,这确实让它变得简单多了。谢谢你的建议。是的,我确实接受了 cdhowie 的回答 :)
    【解决方案3】:

    我将instanceof 视为使用多态性的机会。

    保持someMethod 中所有A 类型通用的行为。子类A 以实现您当前使用instanecof 检查的行为。

    public class A{
    
        public void someMethod(){
    
            // Get rid of the special section and put it in it's own class
            // Keep only agnostic behavior common to all types of A
            // Actions to execute for every call
        }
    }
    
    public class B extends A{
    
       @Override
       public void someMethod(){
    
           super.someMethod();
    
           // More actions
       }
    }
    
    public class C extends A{
    
       @Override
       public void someMethod(){
           super.someMethod();
    
           // Actions that were originally in the if(instanceof) check
       }
    }
    

    【讨论】:

      【解决方案4】:

      这可能与 cdhowie 想说的一样。 (无意冒犯:我以为你有点不清楚。)

      不要使用 instanceof。相反,为给定类型创建返回标志或其他适当值的方法。

      你的例子没有给出你想要做什么的任何细节,所以我只是发明一些东西。

      !!!走错路了!!!

      public class Car
      {
        public void goUphill()
        {
          // XYZ has automatic transmission -- don't need to downshift
          if (!(this instanceof XYZ())
          {
            downshift();
          }
          pressGas();
        }
      }
      
      public class ModelXYZCar extends Car
      {
        public void goUphill()
        {
          tellWifeToGetOutAndPush();
          super.goUphill();
        }
      }
      

      更好的方法:

      public class Car
      {
        public boolean isManualTransmission()
        {
          // default
          return true;
        }
        public void goUphill()
        {
          if (isManualTransmission())
          {
            downshift();
          }
          pressGas();
        }
      }
      
      public class ModelXYZCar extends Car
      {
        public boolean isManualTransmission()
        {
          return false;
        }
        public void goUphill()
        {
          tellWifeToGetOutAndPush();
          super.goUphill();
        }
      }
      

      这样,超类不必知道子类需要什么。每个子类都定义了自己的行为。在这种情况下,每个子类都定义了一个 isManualTransmission 函数,并根据需要返回 true 或 false。

      最好还是避免对标志的需要,并在每个类中放置适当的行为:

      abstract public class Car
      {
        abstract public void downshift();
        public void goUphill()
        {
          downshift();
          pressGas();
        }
      }
      
      public class AutomaticTransmissionCar extends Car
      {
        public void downshift()
        {
          // Automatic transmission -- no need to do anything
        }
      }
      public class ManualTransmissionCar extends Car
      {
        public void downshift()
        {
          ... whatever ...
        }
      }
      public class ModelXYZCar extends ManualTransmissionCar
      {
        public void goUphill()
        {
          tellWifeToGetOutAndPush();
          super.goUphill();
        }
      }
      

      【讨论】:

        【解决方案5】:

        为什么不:

        public class A{
        
            public void someMethod(){
        
            // Only perform these actions if it is not a child class.  This is what
            // I am looking for a better solution for
                if(this.getClass().equals(A.class))
                // Some action...
                }
        
            // Actions to execute for every call
            }
        }
        

        public class B extends A{
        
            @Override
           public void someMethod(){
        
               super.someMethod();
        
               // More actions
           }
        }
        

        【讨论】:

          【解决方案6】:

          表达式A.class.equals(this.getClass()) 仅在这确实是类 A 的实例时才返回 true。如果是子实例,则结果将为 false。

          但是:如果您必须这样做,请检查您的设计。这听起来很不是面向对象的风格。我可以给你一个替代方案。将您的基类 A 分离为 2:真正的基类 A0 及其子类 A1。您的 B 类将是 A1 的兄弟,并将直接从 A0 扩展。

          在这种情况下,您可以将公共代码放入 A0 类,并将所有特定代码(在您的版本中,只有当该类完全是 A 而不是它的子类时才必须执行)到 A1。

          【讨论】:

            【解决方案7】:

            “呼叫超级”is an anti-pattern。不要期望子类调用超类功能,而是反过来。现在,超类可以完全控制“通用”内容之前和之后的内容。

            public class A {
                public void someMethod() {
                    beforeCommonStuff();
                    // Actions to execute for every call
                    afterCommonStuff();
                }
            
                protected void beforeCommonStuff() {
                    // Actions to execute only for class A
                }
            
                protected void afterCommonStuff() {}
            }
            
            public class B extends A {
                @Override
                protected void afterCommonStuff(){
                    // More actions
                }
            }
            

            【讨论】:

            • 这将是模板方法设计模式,并且 A 类中的 someMethod() 方法应标记为 final 以使模式生效。
            【解决方案8】:

            我可能弄错了,但您的案例似乎是“支持组合而不是继承”和“封装变化的内容”的理想场景。在像您这样的情况下,一种一般的行动方案是:

            1. 您的子类没有继承自超类
            2. 在私有方法中隔离应该只属于 A 的代码部分。
            3. 在 B、C 等中创建 A 的实例并调用 A.someMethod()。

              public class A {
                  public void someMethod(){}
                  private void someOtherMethod(){
                      // move behavior specific to A in here.
                  }       
              }
              
              public class B { // no extends
                  public void someMethod() {
                      new A().someMethod();
                  }
              }
              

            同样,我可能是错的,这可能不适用于您的情况。

            【讨论】:

              猜你喜欢
              • 2013-05-17
              • 1970-01-01
              • 2016-07-07
              • 2021-11-20
              • 2019-01-08
              • 1970-01-01
              • 2021-02-01
              • 1970-01-01
              相关资源
              最近更新 更多