【问题标题】:Java - can I extend an instance of a class to make it a parent class instance?Java - 我可以扩展一个类的实例以使其成为父类实例吗?
【发布时间】:2015-11-12 18:32:21
【问题描述】:

这是我想要实现的一个小的人工示例。我有一个有很多参数的类 - Dog。我有一个子类JumpyDog,我想了解如何“扩展”Dog 的实例以使其成为JumpyDog 的实例。

class Dog {
    int age, numberOfTeeth, grumpiness, manyOtherParameters;
    JumpyDog learnToJump(int height) {
        JumpyDog jumpy = new JumpyDog(this); // I do not want to copy all parameters
        jumpy.jumpHeight=height;
        return jumpy;
    }
}

class JumpyDog extends Dog {
    int jumpHeight;
    void jump(){}
}

或者我可以这样说吗:

Dog dog=new Dog();
dog.makeJumpy();
dog.jump()

【问题讨论】:

  • 你希望 Dog 是 JumpyDog 的一个实例,而 JumpyDog 是 Dog 的一个实例?
  • 您想在初始化后更改对象的类型。这在 Java 中是不可能的。您必须将Dog 属性复制到JumpyDog 的新实例中。
  • 不,您不能在实例创建后神奇地切换其类。
  • 我能以某种方式复制所有属性而不命名它们吗?
  • 当您扩展父类 (Dog) 时,所有公共和受保护的属性也会出现在子类 (JumpyDog) 中。您添加了新属性jumpHeight,但您仍然可以不受限制地操作agenumberOfTeeth

标签: java oop inheritance instance maintainability


【解决方案1】:

您可以在 Java 中实现 Decorator pattern 以避免在“扩展”期间复制初始对象的所有字段,方法是在内部保留对它的引用,但它不再是 Dog(因为 Dog 类有我们避免复制的字段)。

class JumpyDog {
    Dog meAsDog;
    int jumpHeight;

    public JumpyDog(Dog me) {
        meAsDog = me;
    }

    public Dog meAsDog() {
        return meAsDog();
    }

    void jump(){}
}

你可以像下面这样使用它:

Dog dog=new Dog();
JumpyDog meAsJumpy = dog.learnToJump(100);
meAsJumpy.jump()

不,您不能从您的示例中执行以下操作,因为 Dog 没有 jump() 方法:

Dog dog=new Dog();
dog.makeJumpy();
dog.jump() // Dog has no method jump

【讨论】:

  • 如果你想让这个更加动态,你可以使用Role Object Pattern,这是一个使用装饰器模式的更大模式。这种简单方法的问题是你会患上客观精神分裂症。
【解决方案2】:

你可以这样做:

class Dog {

    int age;
    int numberOfTeeth;
    int grumpiness;
    int manyOtherParameters;

    boolean hasLearnedHowToJump;
    int jumpHeight;

    void learnToJump(int heigth) {
        hasLearnedHowToJump = true;
        jumpHeight = heigth;
    }

    void jump(){
        if(!hasLearnedHowToJump) {
            throw new RuntimeException("must learn how to jump first...");
        }
    }

}

那么你可以这样使用它:

Dog dog=new Dog();
//dog.jump() would end in a exception...
dog.learnToJump(100);
dog.jump()

【讨论】:

    【解决方案3】:

    一旦dog 被声明为Dog 类型,这将永远是它的类型。你可以将它转换为任何超类,但它仍然是Dog

    您可以使用复制构造函数。这实际上需要您为所有属性编写一些复制代码,但会为您提供接近您想要的样式的东西。

    public class Dog {
    
        int age, numberOfTeeth, grumpiness, manyOtherParameters;
    
        public Dog() {
    
        }
    
        public Dog(Dog other) {
            other.age = this.age;
            other.numberOfTeeth = this.numberOfTeeth;
            other.grumpiness = this.grumpiness;
            other.manyOtherParameters = this.manyOtherParameters;
        }
    }
    
    
    class JumpyDog extends Dog {
    
        int jumpHeight;
        void jump(){}
    
        public JumpyDog(Dog other) {
            super(other);
        }
    
    }
    

    会让你写这样的东西:

    Dog dog = new Dog();
    JumpyDog jumpyDog = new JumpyDog(dog);
    jumpyDog.jump();
    

    给你留下 2 个实例。这将使jumpyDog 跳转,但不会对dog 实例执行任何操作。

    【讨论】:

      【解决方案4】:

      你可以这样做

      class Dog {
          protected int age, numberOfTeeth, grumpiness, manyOtherParameters;
      
          protected Dog(Dog g) {
              // assign all attributes here
          }
      
          JumpyDog learnToJump(int heigth) {
              return new JumpyDog(this, heigth);;
          }
      
      
      }
      
      class JumpyDog extends Dog {
      
          int jumpHeight;
      
          public JumpyDog(Dog dog, int jumpHeight) {
              super(dog);
              this.jumpHeight = jumpHeight;
          }
          void jump(){}
      }
      

      然后你可以这样做:

      Dog dog=new Dog();
      JumpyDog jDog = dog.learnToJump(100);
      jdog.jump()
      

      【讨论】:

      • 这里是在“assign all attributes”中复制,作者要避免
      • 这个构造函数可以由所有 IDE 生成,因为属性在同一个类(Dog)中。
      【解决方案5】:

      最好的方法是实现链接文件中描述的Role Object Pattern。这是@Philip Voronov 已经建议的类似装饰的模式。有一个概念作为接口,由一个核心和一个抽象类实现,该抽象类代表一个对象可以扮演的所有角色的超类。为了缓解object schizophrenia(当逻辑单元对象在许多物理对象之间拆分时出现),每次调用角色对象(不是角色特有的)都被转发到核心对象。

      从逻辑上讲,核心及其角色构建了一个单元。但是对象被拆分为核心(管理角色)和对象可以扮演的所有角色。

      客户端要么与核心对象对话,要么与角色对象对话。您可以在运行时添加和删除角色。

      我用你的狗场景写了a short implementation

      它提供了逻辑狗(世界已知的狗的概念)与其所有能力之间的分离。因此,您不必先验地知道这些能力。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-21
        相关资源
        最近更新 更多