Search code examples
javaclassobjectinheritancecomposition

Is there a way to propagate changes to variables within a class instance to other class instances derived from it?


Problem: What I want to achieve is to have an instance of a Parent class propagate changes of its local variables to Child class instances derived directly from the Parent. My current approach is to extend the Parent class to the Childs but it doesn't provide any way to access the Parent instance variables.

Example: Let's say that the parent class stores a String which contains a name. I want 1 child to stem from a parent whose String name is "George" and 1 other child to stem from a parent whose String name is "Nick". When the String stored in the "George" parent class changes from "George" to "Patrick" I want it to be changed for his child but not for the child of "Nick".

Can this be done without too much computational overhead?

Code Reference:

public class Parent {
    private String name;

    public Parent(String name) {
        this.name = name;
    }

    public void changeName(String newName) {
        name = newName;
    }

    public String getName() {
        return name;
    }
}

public class Child extends Parent {
    private String parentName;
    /**
     * Currently derives the String directly which won't react to
     * changes to the Parent class.
     */
    public Child(Parent p) {
        this.parentName = p.getName();
    }

    public getParentName() {
        return parentName;
    }
}

public class mainApp {
    public static void main(String[] cmdArgs) {
        Parent George = new Parent("George");
        Parent Nick = new Parent("Nick");

        Child a = new Child(George);
        Child b = new Child(Nick);

        George.changeName("Patrick");

        // Prints "George", should print "Patrick"
        System.out.println(a.getParentName());

        // Prints "Nick", should print "Nick"
        System.out.println(b.getParentName());
    }
}

Solution: It is actually possible to achieve the above by using Object Composition.

By keeping a reference to the original Parent that was used when creating the Child class instance, all changes conducted on the Parent instance will be reflected on the Child instance.

In this way, a Child can also be in an orphaned state where no Parent instance was used to create it.

Solution Code:

public class Parent {
    private String name;

    public Parent(String name) {
        this.name = name;
    }

    public void changeName(String newName) {
        name = newName;
    }

    public String getName() {
        return name;
    }
}

// Extension is not required
public class Child {
    private Parent parentReference;

    public Child(Parent parentReference) {
        this.parentReference = parentReference;
    }

    public getParentName() {
        // We need to manually handle the case of a non-existent parent
        if (parentReference == null) {
            return "None";
        } else {
            return parentReference.getName();
        }
    }
}

public class mainApp {
    public static void main(String[] cmdArgs) {
        Parent George = new Parent("George");
        Parent Nick = new Parent("Nick");

        Child a = new Child(George);
        Child b = new Child(Nick);
        Child c = new Child(null);

        George.changeName("Patrick");

        // Prints "Patrick", should print "Patrick"
        System.out.println(a.getParentName());

        // Prints "Nick", should print "Nick"
        System.out.println(b.getParentName());

        // Prints "None", should print "None"
        System.out.println(c.getParentName());
    }
}

Solution

  • You're taking the terms "Parent" and "Child" in a very literal sense in your example but that is not always applicable.

    You can only use inheritance when there is a fixed relationship between a type and a subtype. Like, "a Bicycle is a Vehicle" or a "Giraffe is an Animal". Those relations are the same for every instance of Bicycle and Giraffe. But what you're describing is not like this.

    For your case, you can use composition to model.

    • Every Person has a name.
    • Every Person has a parent (which may be left null to indicate "don't know" or "don't care")
    • Every Person has zero or more children
    class Person {
        String name;
        Person parent;
    
        Person(String name, Person parent) {
            this.name = name;
            this.parent = parent;
        }
    
        // etc (getters, setters)
    }
    
    public class MainApp {
        public static void main(String[] cmdArgs) {
            Person george = new Person("George", null);
            Person nick = new Person("Nick", null);
            Person a = new Person("a", george);
            Person b = new Person("b", george);
            Person c = new Person("c", nick);
            // etc.
        }
    }