Looks like a template method pattern.
But then you must implement Foo.checkable()
and introduce another abstract method to delegate to.
abstract class Foo{
public Foo(){}
public void checkable(){
calledWhenCheckableIsCalled();
doCheckable();
}
protected abstract void doCheckable();
public void calledWhenCheckableIsCalled(){
System.out.println("checkable was called");
}
}
I would also suggest to make checkable()
final in this case so that you can be sure that checkable()
can not implemented in another way as you expected.
In addition to Brian Roach's comment
The downside is that the protected can be expanded to public in the subclass, so you can't explicitly enforce it.
That's true, but you can prevent a Foo
instance from being instantiated if a subclass increases the visibility of doCheckable
. Therefore you have to introduce a verification whenever an object is instantiated. I would recommend to use an initializer code so that the verification is executed on every constructor that exists. Then it can not be forgotten to invoke and therefore be by-passed.
For example:
abstract class Foo {
{ // instance initializer code ensures that enforceDoCheckableVisibility
// is invoked for every constructor
enforceDoCheckableVisibility();
}
public Foo() {...}
public Foo(Object o) {...}
private void enforceDoCheckableVisibility() {
Class<?> currentClass = getClass();
while (currentClass != Foo.class) {
try {
Method doCheckableMethod = currentClass.getDeclaredMethod("doCheckable");
if (Modifier.isPublic(doCheckableMethod.getModifiers())) {
throw new RuntimeException("Visibility of "
+ currentClass.getSimpleName()
+ ".doCheckable() must not be public");
}
} catch (SecurityException | NoSuchMethodException e) {}
currentClass = currentClass.getSuperclass();
}
}
}
Since the check is implemented using reflection the downside is that it is only checked at runtime. So you will not have compiler support of course. But this approach let you enforce that an instance of a Foo
can only exist if it fulfills your contract.