One of the best ways to understand the relevance of the Liskov Substitution Principle is by showcasing a case where its unintentional violation makes an application crash noisily. Recently I went through a situation that made me learn this lesson the hard way. Simply put, all that I needed to do was add a small view rendering layer to a client's existing framework, which in turn allowed them to create master web page layouts and partials (views placed inside of other views) in a straightforward fashion. I normally use Zend Framework for my work, but given the simplicity of this particular project I thought a good approach to tackle the problem would be to appeal to the functionality of the Composite View pattern. Given that, I started looking into some libraries written in the past and came up with a simple hierarchy of composite classes, whose abstract parent looked like this (edited for the sake of brevity):
/** * Unset the specified field from the view */ public function __unset($name) { if (isset($this->_values[$name])) { unset($this->_values[$name]); return true; } return false; } /** * Render the template */ protected function _doRender() { if ($this->_template !== null) { extract($this->_values); ob_start(); include $this->_template; return ob_get_clean(); } return ''; } /** * Get an associative array with the values assigned to the fields of the view */ public function toArray() { return $this->_values; } abstract public function addView(AbstractView $view); abstract public function addViews(array $views); abstract public function removeView(AbstractView $view); abstract public function render(); } Even though the implementation of this base class seems to be rather complex, its functionality is simply limited to associating a template file (usually an entire web page or a section of it) to a view object, which can be assigned/removed dynamically a bunch of properties, thanks to the magic of the “__set()”, “__isset()”, “__unset()” and “__get()” PHP methods. Finally, the template can be internally rendered via the protected “_doRender()” method, which uses some output buffering to get the job done with minor hassles. With this abstraction living comfortably on top of the hierarchy, the next step that I needed to take was to spawn a couple of concrete subclasses, capable of dealing with composite views and partials respectively (notice that set of abstract methods declared by the parent for this purpose). Again, I remembered that the task was pretty easy to accomplish and ended up creating a pair of derivatives, where the implementation of the first one was as follows:
At this point, the scenario was looking even better, as I had managed to set up a composite view class capable of rendering itself along with other views attached via the “addView() and “addViews()” methods. To get things up and running though, I needed to derive yet another subclass, tasked with rendering partials. So, I put my hands back on the keyboard and built the following one:
At first I felt a little uncomfortable making the “addView()”, “addViews()” and “removeView()” methods of the earlier subclass to throw some exceptions, as this was a clear sign that something wasn’t exactly right - but since the derivative was responsible for rendering partials, I quickly changed my mind and forgot about this potential issue. With this hierarchy of composite view classes ready to go, the last thing that I needed to do was create a few PHP templates, and check if the classes in question were that functional so that they could fit my client’s requirements. Thus, I defined three trivial templates, which looked like this:
Finally, after doing some unit testing, the composite view layer was ready for some real action! Since I was feeling a bit smug with the neat results achieved so far, I simply built up a script to put the composite classes to work. The script was similar to the one below (I decided to omit the autoloader’s implementation to keep the whole code uncluttered and easier to read):
As seen above, my testing script firstly spawned a composite view object, which was fed in turn with three different partials, containing the “header.php”, “body.php” and “footer.php” templates defined before. After running the pertaining script in the server, it nicely rendered the following output:
That worked like a charm. Even when there was still a little voice in my head warning me that the implementation of the earlier “PartialView” class wasn’t entirely correct, in general I was pretty satisfied with the functionality of my composite view layer. Therefore, I contacted the client with the good news, sent him the source files and finally got my payment. Everything was goin fine until my client called me back a few weeks later telling me that he also needed to implement a small application for building some web page layouts in an automated way, which would use my composite view layer. He asked me, "Can this be done in a timely manner?" Of course I answered with a resounding: "yes!" Then I launched my code editor and started writing a simple layout builder class. To my surprise, the task would be a pain, due to the wrong hierarchy of classes built in the past.
blog comments powered by Disqus |
|
|
|
|
|
|
|