6

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()
Blake Yarbrough
  • 2,286
  • 1
  • 20
  • 36
G33K
  • 249
  • 4
  • 11
  • You want Dog to be an instance of JumpyDog while JumpyDog is an instance of Dog? – CPerkins Aug 19 '15 at 12:43
  • You want to change the type of an object after it was initialized. This is not possible in Java. You will have to copy the `Dog` properties into a new instance of `JumpyDog`. – dotvav Aug 19 '15 at 12:45
  • no, you cannot magically switch class of an instance after its creation. – Alex Salauyou Aug 19 '15 at 12:47
  • Can I somehow copy all the properties without naming them? – G33K Aug 19 '15 at 12:47
  • When you extend a parent class (`Dog`) all public and protected properties become presented also in a child class (`JumpyDog`). You add new property `jumpHeight`, but you can still operate `age`, `numberOfTeeth` without restrictions. – Alex Salauyou Aug 19 '15 at 12:49
  • I think you'll be better off explaining what use case lead you to want this feature. There is probably a much better design alternative, and once we understand your actual requirement, I'm sure someone will point out the better way of achieving that. [What is the XY problem?](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) – sstan Aug 19 '15 at 12:51
  • You can define abstract jump() in Dog and implement it in JumpyDog. -- Dog dog = new JumpyDog(); dog.jump(); – Ravindra babu Aug 19 '15 at 12:56
  • Ideally Dog is not supposed to know about skills of its children. – G33K Aug 19 '15 at 13:00

5 Answers5

3

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
Filipp Voronov
  • 4,077
  • 5
  • 25
  • 32
  • 1
    If you want to make this much more dynamic you can use the `Role Object Pattern` which is a bigger pattern using the decorator pattern. The problem with this simple approach is that you are going to have object schizophrenia. – lschuetze Aug 19 '15 at 13:04
1

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.

lschuetze
  • 1,218
  • 10
  • 25
0

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()
StefanHeimberg
  • 1,455
  • 13
  • 22
0

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.

dotvav
  • 2,808
  • 15
  • 31
0

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()
clapsus
  • 442
  • 6
  • 19