Is there anyway (or a pattern) to enforce a call to a parent method?
I have an abstract class like so:
abstract class APrimitive{
public function validate(){
//Do some stuff that applies all classes that extend APrimitive
}
}
Then I have classes that extend upon the APrimitive "base":
class CSophisticated extends APrimitive{
public function validate(){
//First call the parent version:
parent::validate();
//Then do something more sophisticated here.
}
}
The problem is that if we come back to the code in a few months time, and create a few more classes like CSophisticated with a validate()
method, there is a possibility that we might forget to make a call to parent::validate()
in that method.
Note that some CSophisticated classes may not have the validate()
method, so the parent version will be called.
I understand that it is possible to just put in a comment somewhere, to remind the programmer to call parent::validate()
, but is there a better way? Perhaps an automated way to throw an exception if the call to parent::validate()
was not made in the validate()
method would be nice.
You can enforce the call with the following:
abstract class APrimitive{
final public function validate(){
//do the logic in validate
overrideValidate();
}
protected function overrideValidate(){
}
}
class CSophisticated extends APrimitive{
protected function overrideValidate(){
}
}
Now only calls to validate
are permitted, which will in turn call your overridden method. The syntax may be a little off (PHP
is not my language of choice) but the principle is applyable to most OOP languages.
FURTHER EXPLANATION:
abstract class APrimitive{
public function validate(){
echo 'APrimitive validate call.';
overrideValidate();
}
protected function overrideValidate(){
}
}
class CSophisticated extends APrimitive{
protected function overrideValidate(){
echo 'CSophisticated call.';
}
}
CSophisticated foo;
foo.overrideValidate(); //error - overrideValidate is protected
foo.validate(); //
Output:
APrimitive validate call.
CSophisticated call.
The function call basically does the following:
foo.validate() -> APrimitive.validate() -> ASophisticated.overrideValidate() (or APrimitive.overrideValidate() if it wasn't overriden)
You're looking for The Template Method pattern.
This pattern allows you to modify an operation in some way through sub-classing but ensures that the base class is always involved.
class Base {
//declared final so it can't be overridden
public final function validate() {
//perform base class operations here
//then forward to the sub class
$this->doValidate();
//do some more base class stuff here if needed
}
//override this method to alter validate operation
protected function doValidate(){
//no-op in base
}
}
class Sub {
protected function doValidate() {
//if required
//make the sub-class contribution to validate here
}
}