简体   繁体   中英

Java - can I extend an instance of a class to make it a parent class instance?

Here is a small artificial example of what I am trying to achieve. I have a class with many parameters - Dog . I have a child class JumpyDog and I want to learn how can I can "extend" the instance of Dog to make it an instance of 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(){}
}

Or can I say something like that:

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

You can implement Decorator pattern in Java to avoid copying all fields from initial object during your "extension" by just internally keeping the reference to it, but it won't be Dog anymore (because Dog class has fields we avoiding to copy).

class JumpyDog {
    Dog meAsDog;
    int jumpHeight;

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

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

    void jump(){}
}

You can use it like the following:

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

And no, you can not do the following from your example because Dog hasn't jump() method:

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

you could do something like this:

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...");
        }
    }

}

then you can use it like that:

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

Once dog has been declared of type Dog this is its type forever. You may cast it to any super-class but it will still be a Dog .

You may use a copy constructor. That actually requires you to write some copying code for all the attributes, but will offer you something close to your desired style.

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);
    }

}

Will let you write something like:

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

Leaving you with 2 instances. That will make jumpyDog jump, but will do nothing on the dog instance.

You can do something like this

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(){}
}

Then you can do some like this:

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

The best would be to implement the Role Object Pattern described by the linked paper. It is a decorate like pattern already suggested by @Philip Voronov. There is a concept as interface that is implemented by a core and an abstract class representing the super class of all roles that can be played by an object. To mitigate object schizophrenia (which appears when logical unit objects are split among many physical objects) every call to role object (which is not peculiar to the role) is forwarded to the core object.

Logically the core and its roles build a single unit. But the object is split into the core (which manages the roles) and all roles that can be played by the object.

Clients either talk with the core object or with the role objects. You can add and remove roles at runtime.

I have written a short implementation using your dog scenario.

It provides separation between the logical dog (the concept of Dog known to the world) and all its abilities. Therefor you do not have to know the abilities a-priori.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM