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.