Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design patterns - anti pattern call super - avoid or keep

I recently noticed that something I actually liked doing in certain cases (call super) is an anti-pattern. (http://en.wikipedia.org/wiki/Call_super)

So my question is:

How to do the following thing (a basic thing that most of us need, add some details to an object). I'll just add a new element to an array that is hold in an object var:

   <?php
   class A {
       // bla bla bla
       public function __construct() {
            $this->_data['newDetail'] = "Ipiicaei";
       }
   }


   class B extends A {
       // bla bla bla
       // Override constructor, I need to add one more detail for this class
       public function __construct() {
            parent::__construct();
            $this->_data['newDetailSubcls'] = "Something";
       }
   }

Now... if I don't call the parent class constructor to add the first element, I have 2 possibilities:

  1. In each subclass add the part of code that the parent is normally doing, and remove it from parent. So if I extend it with 999 classes I'll duplicate 999*lines in parent. Sounds bad to me.

  2. Call a method from parent that is implemented in child (template method pattern, what they recommend). So if I need for only one class to add that, and the rest of 998 to behave exactly like the parent, in each of them I add an empty function. This also sounds bad to me.

Bear in mind that my example is simple (that's how an example should be), but the parent class and/or subclass might do complicated things.

I can see reasons why call super may be bad in some situations. But in this one seems ok to me.

So... how would you approach? Ignore that call super is an anti-pattern and do as I do (or used to do if it turns out my way is bad)? Or... how?

like image 250
zozo Avatar asked Oct 04 '22 19:10

zozo


1 Answers

Using constructors is sort of a bad example of how this anti-pattern emerges, since in PHP like in most languages that support inheritance,

If the child does not define a constructor then it may be inherited from the parent class just like a normal class method ... (from the PHP manual).

If in any of the other 998 classes you are trying to define you purposely do not include a constructor, the base constructor will get called, making it pretty much a requirement to add a constructor on each derived class to avoid this functionality. This is why is not recommend to add logic in a constructor that might alter the state of protected fields/properties or to call virtual methods that might be overridden in derived classes.

However, the anti-pattern actually expresses that:

Note that it is the requirement of calling the parent that is the anti-pattern (from Wikipedia)

So, it is OK to call the base class version of a method as long as it is not required to do so by a derived class. The derived class must behave correctly even though the base method is never called. This will avoid the scenario where a derived class overrides a virtual method but does not implement some special requirement (perhaps because of lack of documentation on the base class), at which point the derived class does not behaves as expected by the system, potentially causing the system to crash or behave unexpectedly, a typical violation of the Liskov substitution principle.

In your particular example this anti-patter does not apply: you're extending constructors, which by definition are required to be called as they instantiate the class into a useful state. And in most instances that's what you want.

like image 68
rae1 Avatar answered Oct 11 '22 17:10

rae1