Home > OS >  How can each derived class can have its own static value, while sharing the same base method in Java
How can each derived class can have its own static value, while sharing the same base method in Java

Time:11-14

class Base {
    Base() {
        System.out.println("Base Constructor");
    }
}

class Derived1 extends Base {
    private static String pattern = "a b ";
    Derived1() {
        super();
        System.out.println("Derived 1 Constructor");
    }

    public static boolean doesMatch(String v) {
        return v.matches(pattern);
    }
}

class Derived2 extends Base {
    private static String pattern = "c ";
    Derived2() {
        super();
        System.out.println("Derived 2 Constructor");
    }
    
    public static boolean doesMatch(String v) {
        return v.matches(pattern);
    }
}

class Builder {
    public static Base baseFromString(String v) throws Exception {
        if (Derived1.doesMatch(v)) return new Derived1();
        if (Derived2.doesMatch(v)) return new Derived2();
        throw new Exception("Could not match "   v   " to any derived type.");
    }
}

class Test {
    public static void main(String[] args) throws Exception {
        Base b = Builder.baseFromString("aaab");
    }
}

The code above has a primary problem I want to solve:

  1. The doesMatch method is repeated code for the two derived classes. I'd like to move it to the base class, but then it won't be able to access the pattern member. How do I structure my code better so that each derived class can have its own static pattern, while they all share the same base doesMatch method?

I've tried messing around with abstract classes and interfaces, but I couldn't get anything to work. I am fine with those types of solutions as long as there is a hierarchy where the derived classes either extend or implement the base class.

Secondary question (from original post)

  1. I might want to add several more derived classes. I'd like to not have to update the baseFromString method with another if every time I extend the base class. Is this something that can be solved with polymorphism?

CodePudding user response:

A functional technique (Java 9 ), but there is some performance overhead:

class Base {
    Base() {
        System.out.println("Base Constructor");
    }
}

class Derived1 extends Base {
    Derived1() {
        super();
        System.out.println("Derived 1 Constructor");
    }
}

class Derived2 extends Base {
    Derived2() {
        super();
        System.out.println("Derived 2 Constructor");
    }
}

interface NewBase {
    Base create();
}

final class Pattern {
    final private String pattern;
    final private NewBase newBase;
    public Pattern(String pattern, NewBase newBase) {
        this.pattern = pattern;
        this.newBase = newBase;
    }
    public String getPattern() {
        return pattern;
    }
    public NewBase getNewBase() {
        return newBase;
    }
}

class Builder {
    final private static List<Pattern> newObjects = new ArrayList<>();
    private static void addPattern(String pattern, NewBase newObject) {
        newObjects.add(new Pattern(pattern, newObject));
    }
    static {
        addPattern("a b ", Derived1::new);
        addPattern("c ", Derived2::new);
    }
    public static Base baseFromString(String v) throws Exception {
        for (Pattern p : newObjects) {
            if (v.matches(p.getPattern()))
                return p.getNewBase().create();
        }
        throw new Exception("Could not match "   v   " to any derived type.");
    }
}

Just update the static Builder initializer to call the addPattern for new patterns and derived classes.

CodePudding user response:

You can't do that, at least not with static members. The problem is that static members cannot be overridden.

public class Driver {
    public static void main(String args[]) {
        Derived aDerived = new Derived();
        aDerived.print(); // prints "Value is 5", not "Value is 10"
    }
}

public class Base {
    protected static final int VALUE = 5;
    public Base() {}
    
    protected void print() {
        System.out.println("Value is "   VALUE);
    }
}


public class Derived extends Base {
    protected static final int VALUE = 10; // does not override base Value
    public Derived() {}
}

Each subclass can have its own value, and they would all inherit print(). But it doesn't do what you want because print() will always reference Base.VALUE even in the inherited Derived.print().

So, static doesn't work. I assume that you feel the pattern member needs to be static because there only needs to be one copy of the pattern value for the entire class. That one copy part should have tipped you off to a handy little design pattern: the singleton pattern!

public class Driver {
    public static void main(String args[]) {
        Derived aDerived = new Derived();
        aDerived.print(); // prints "Value is 10"
    }
}

public class Base {
    protected Value val = Value.getInstance();
    public Base() {}
    
    protected void print() {
        System.out.println("Value is "   val.value());
    }
}

public class Derived extends Base {
    public Derived() { val = DerivedValue.getInstance(); }
}

public class Value {
    private int value = 5;
    public int value() { return value; }

    private static Value instance = new Value();
    protected Value() {}
    public static Value getInstance() { return instance; }
}

public class DerivedValue extends Value {
    private int value = 10;
    public int value() { return value; }

    private static DerivedValue instance = new DerivedValue();
    private DerivedValue() {}
    public static DerivedValue getInstance() { return instance; }
}

There's a lot more code in this version, but now there is only one copy of the two different values used.

Note: Below is how you can make the value members final. You'll have to set up your packages appropriately so the protected Base(Value v) constructor is only visible to the Derived class.

public class Base {
    protected final Value val;
    public Base() { val = Value.getInstance(); }
    protected Base(Value v) { val = v; }
    
    protected void print() {
        System.out.println("Value is "   val.value());
    }
}

public class Derived extends Base {
    public Derived() { super(DerivedValue.getInstance()); }
}
  • Related