简体   繁体   中英

Abstract class get parameter from implementing subclass?

I'm wondering if there is way to do this without breaking encapsulation, I want the abstract class to rely on parameters defined in the implementing subclass. Like so:

public abstract class Parent {

    private int size;
    private List<String> someList;

    public Parent() {
        size = getSize();
        someList = new ArrayList<String>(size);
    }

    public abstract int getSize();

}

public class Child extends Parent {

    @Override
    public int getSize() {
        return 5;
    }

}

Is this ugly? Is there a better way? And perhaps more importantly, is this even a good idea?

EDIT:

The classes are created in the context of a framework, so the default parameter-less constructor is always the one called (in fact, the Parent class extends another class). The size parameter is just used for illustration purposes and I don't plan on using it for a List implementation.

No, is not ugly. This pattern is named "template method". But typically it is more useful when the method is not a simple getter but something that implement business logic.

In your case other solution is to define protected constructor in Parent class and call it with relevant parameter from child:

public abstract class Parent {

    private int size;
    private List<String> someList;

    protected Parent(int size) {
        this.size = size;
        someList = new ArrayList<String>(size);
    }

    public int getSize() {
        return size;
    }

}

public class Child extends Parent {
    public Child() {
        super(5);
    }
}

If the constructor is the only place you use getSize() , just require it as a constructor parameter.

But more importantly, why do you care about size? Unless you know there's a problem, just use the default size like everybody else:

public abstract class Parent {

    private List<String> someList = new ArrayList<String>();

    // use default constructor    
}

The pattern is not ugly, except when you try to use it in the constructor. It allows you to modify Child in a way that results are unexpected.

public class Child extends Parent {

    private int mySize = 5;

    @Override
    public int getSize() {
        // The -1 is only to help clarify what happens
        return mySize - 1;
    }

}

If you now create an instance of Child it would actually throw an exception because a negative capacity is not allowed. You should realize that the properties of a class are only initialized after the parent constructor has finished. (And if a property is set using the Parent constructor and has a default value defined in Child, it will happily overwrite the value you just set in Parent() )

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