Hot File

Reusing Implementation – a Walk-through of Inheritance, Composition, and Delegation

View: 259    Dowload: 0   Comment: 0   Post by: hanhga  
Author: none   Category: Php&mySql   Fields: Other

9 point/2 review File has been tested

It shouldn’t be breaking news that the first code reuse approach I plan to put in the spotlight first is the most overused and misused of all, Inheritance.

Introduction

It shouldn’t be breaking news that the first code reuse approach I plan to put in the spotlight first is the most overused and misused of all, Inheritance. But I don’t want to be a sadist and bore you to tears (and myself, of course) explaining how to get a nice Dog subclass up and running by inheriting from Animal (ouch!). Rather, I’ll be a little more realistic and we’ll sink our teeth into a naïve, yet functional, PDO adapter. Here we go:

<?php
namespace LibraryDatabase;

interface DatabaseAdapterInterface
{
    public function executeQuery($sql, array $parameters = array());
}
<?php
namespace LibraryDatabase;

class PdoAdapter extends PDO implements DatabaseAdapterInterface
{
    protected $statement;
    
    public function __construct($dsn, $username = null, $password = null, array $options = array()) 
    {
        // fail early if the PDO extension is not loaded
        if (!extension_loaded("pdo")) {
            throw new InvalidArgumentException(
                "This adapter needs the PDO extension to be loaded.");
        }
        // check if a valid DSN has been passed in
        if (!is_string($dsn) || empty($dsn)) {
            throw new InvalidArgumentException(
                "The DSN must be a non-empty string.");
        }
        // try to create a valid PDO object
        try {
            parent::__construct($dsn, $username, $password,
                $options);
            $this->setAttribute(PDO::ATTR_ERRMODE,
                PDO::ERRMODE_EXCEPTION);
            $this->setAttribute(PDO::ATTR_EMULATE_PREPARES,
                false);
        
        }
        catch (PDOException $e) {
            throw new RunTimeException($e->getMessage());
        }
    }
    
    public function executeQuery($sql, array $parameters = array())
    {
        try {
           $this->statement = $this->prepare($sql);
           $this->statement->execute($parameters);
           return $this->statement->fetchAll(PDO::FETCH_CLASS,
               "stdClass"); 
        
        }
        catch (PDOException $e) {
            throw new RunTimeException($e->getMessage());
        }
    }
}

When it comes to creating a quick and dirty adapter that just adds some extra functionality to the one provided by the PDO class, Inheritance is indeed a pretty tempting path. In this case, the adapter performs some basic validation on the inputted database arguments and its executeQuery() method allows us to run parameterized queries via an easily consumable API. The following snippet demonstrates how to drop the adapter into client code to pull in a few users from the database:

<?php
use LibraryLoaderAutoloader,
    LibraryDatabasePdoAdapter;
    
require_once __DIR__ . "/Library/Loader/Autoloader.php";
$autoloader = new Autoloader;
$autoloader->register();

$adapter = new PdoAdapter("mysql:dbname=mydatabase",
    "myfancyusername", "myhardtoguesspassword");

$guests = $adapter->executeQuery("SELECT * FROM users WHERE role = :role", array(":role" => "Guest"));

foreach($guests as $guest) {
    echo $guest->name . " " . $guest->email . "<br>";
}

There are no smelly signs of any “incidental” breakages of the LSP, meaning that any instance ofPdoAdapter could be safely swapped out at runtime by a base PDO object without complaints from the client code, and the adapter has been blessed with all the legacy functionality encapsulated by its parent. Can we dare to ask for a better deal?

Admittedly, there’s a catch. While not explicit, PdoAdapter is actually exposing to the outside world the whole verbose PDO API, plus the one implemented on it’s own. There might be occasions where we want to avoid this, even if the “IS-A” relation between PdoAdapter and PDO is neatly maintained.

We could appeal to the wisdom of the mantra “favor Composition over Inheritance” in such situations and effectively shift into the seas of Composition. In doing so, we would be effectively reusing PDO’s implementation, but without having to deal with its entire API. Better yet, since there wouldn’t be a “IS-A” relationship, but instead a “HAS-A” one between the corresponding adapter and the PDO class, we’d be also satisfying our purist OOP instincts. Encapsulation would keep its pristine shell intact.

Of course, one nice way to understand the inner workings of this approach is by setting up a concrete example. Let’s tweak the previous PdoAdapter class to honor the commandments of Composition.

Composition over Inheritance – of Adapters, Adaptees, and Other Funny Facts

Contrary to popular opinion, it’s ridiculously easy to implement a PDO adapter that rests on the pillars of Composition. Furthermore, the whole refactoring would be limited to just creating a simple wrapper which would inject a native PDO object into the constructor. Once again, a hands-on example is the best teacher when it comes to understanding the driving logic of the process:

<?php
namespace LibraryDatabase;

interface DatabaseAdapterInterface
{
    public function executeQuery($sql, array $parameters = array());
}
<?php
namespace LibraryDatabase;

class PdoAdapter implements DatabaseAdapterInterface
{
    protected $pdo;
    protected $statement;
    
    public function __construct(PDO $pdo) 
    {
        $this->pdo = $pdo;
        $this->pdo->setAttribute(PDO::ATTR_ERRMODE,
            PDO::ERRMODE_EXCEPTION);
        $this->pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,
            false);
    }
    
    public function executeQuery($sql, array $parameters = array())
    {
        try {
           $this->statement = $this->pdo->prepare($sql);
           $this->statement->execute($parameters);
           return $this->statement->fetchAll(PDO::FETCH_CLASS,
               "stdClass"); 
        }
        catch (PDOException $e) {
            throw new RunTimeException($e->getMessage());
        }
    }
}

While the refactored version of the adapter follows in general the formal definition of the Adapter pattern, the adaptee passed along into the adapter’s internals is, in this case, a concrete implementation rather than an abstraction. Considering that we’re attempting to design a slimmed down API for a PDO object, it doesn’t hurt to be pragmatic and inject the object directly in question without having to go through the hassle of defining an extra interface. If you feel a little more comfortable picking up the interface-based approach, just go ahead and stick to it all the way.

Leaving out of the picture those subtle implementation details, by far the most relevant thing to point out is the PdoAdapter class is now is a less verbose creature. Using Composition, it hides the whole PDO API from the outside world by exposing only its executeQuery() method to client code. Although naïve, the example raises a few points worth noting. First, the burden of dealing with potentially dangerous class hierarchies, where subtypes might behave wildly different from their base types blowing away application flow, has quietly vanished in thin air. Second, not only now is the adapter’s API less bloated, it declares an explicit dependency on a PDO implementation, which makes it easier to see from the outside the collaborator it needs to do its thing.

Yet this slew of benefits come with a not-so-hidden cost: in more realistic situations, it might be harder to create “composed” adapters than it is to create “inherited” ones. The correct path to tread will vary from case to case; be rational and choose the one that fits your requirements the best.

If you’re wondering how to get things rolling with the refactored PdoAdapter class, the following example should be instructive:

<?php
$pdo = new PDO("mysql:dbname=mydatabase",
    "myfancyusername", "myhardtoguesspassword");
$adapter = new PdoAdapter($pdo);

$guests = $adapter->executeQuery("SELECT * FROM users WHERE role = :role", array(":role" => "Guest"));

foreach($guests as $guest) {
    echo $guest->name . " " . $guest->email . "<br>";
}

By now we’ve seen at a very broad level two common approaches that can be employed for reusing implementation. So, what comes next? Well, I promised to dig deeper into the niceties of Delegation, too. While admittedly Composition is an implicit form of Delegation, in the earlier example the delegation link was set by declaring a dependency on a PDO implementation in the constructor.

It’s feasible, however, to get a decent delegation mechanism up and running by using one or multiple factory methods, even though this misses much of the advantages of decoupling interface from implementation. Regardless, it’s worth looking at this approach as it comes in helpful for building PDO adapters capable of lazy connections to the database.

Deferring Database Trips through Delegation

Can anything be more delightful than delaying an expensive database trip to the last minute? Avoiding it completely would certainly be better, which is the prime reason why cache system live and breath. But unfortunately, we just can’t have it all sometimes and we need to settle ourselves by designing PDO adapters that encapsulate this nifty ability inside the boundaries of a factory method.

Delegation is a simple yet powerful pattern that allows to implement this feature without much hassle. If we would turn our attention to the previous PdoAdapter class and make it exploit the benefits of Delegation, it would look as follows:

<?php
namespace LibraryDatabase;

interface DatabaseAdapterInterface
{
    public function connect();

    public function disconnect();

    public function executeQuery($sql, array $parameters = array());
}
<?php
namespace LibraryDatabase;

class PdoAdapter implements DatabaseAdapterInterface
{
    protected $config = array();
    protected $connection;
    protected $statement;
    
    public function __construct($dsn, $username = null, $password = null, array $options = array())
    {
        // fail early if the PDO extension is not loaded
        if (!extension_loaded("pdo")) {
            throw new InvalidArgumentException(
                "This adapter needs the PDO extension to be loaded.");
        }
        // check if a valid DSN has been passed in
        if (!is_string($dsn) || empty($dsn)) {
            throw new InvalidArgumentException(
                "The DSN must be a non-empty string.");
        }
        $this->config = compact("dsn", "username",
            "password", "options");
    }
    
    public function connect()
    {
        if ($this->connection) {
            return;
        }
        try {
            $this->connection = new PDO(
                $this->config["dsn"], 
                $this->config["username"], 
                $this->config["password"], 
                $this->config["options"]
            );
            $this->connection->setAttribute(PDO::ATTR_ERRMODE,
                PDO::ERRMODE_EXCEPTION);
            $this->connection->setAttribute(
                PDO::ATTR_EMULATE_PREPARES, false);
        }
        catch (PDOException $e) {
            throw new RunTimeException($e->getMessage());
        }
    }
    
    public function disconnect()
    {
        $this->connection = null;
    }
    
    public function executeQuery($sql, array $parameters = array())
    {
        $this->connect();
        try {
           $this->statement = $this->connection->prepare($sql);
           $this->statement->execute($parameters);
           return $this->statement->fetchAll(PDO::FETCH_CLASS,
               "stdClass"); 
        }
        catch (PDOException $e) {
            throw new RunTimeException($e->getMessage());
        }
    }
}

If you’ve ever had the chance to craft your own PDO masterpiece from scratch, or if you’ve just reused one of the heap available in the wild, the underlying logic of the above adapter should be pretty easy to grasp. Unquestionably, its most engaging facet is the implementation of the connect() method, as its responsibility is to create a PDO object on request which is then used in turn to dispatch queries against the database.

While admittedly this is pretty dull and boring, it’s helpful for showing how to use a sort of “hard-coded” Delegation in the implementation of adapters which are clever enough for triggering lazy connections to the database. Furthermore, the example below demonstrates how to put the adapter to use:

<?php
$adapter = new PdoAdapter("mysql:dbname=mydatabase",
    "myfancyusername", "myhardtoguespassword");

$guests = $adapter->executeQuery("SELECT * FROM users WHERE role = :role", array(":role" => "Guest"));

foreach($guests as $guest) {
    echo $guest->name . " " . $guest->email . "<br>";
}

Call me an unbearable pedantic if you want to, but consuming the adapter is actually a simple process, especially when analyzed from the client code’s standpoint. The major pitfall is that the adapter hides a dependency. This introduces a nasty coupling, hence making the whole implementation a little bit dirty. On the flip side, the adapter’s most appealing virtue rests with its capability for calling the database only when the situation warrants. Naturally, this sort of trade off can be worked out pretty easily by injecting a factory in the adapter, which would be charged with creating a PDO object when needed.

Even though this approach effectively is the best of both worlds, since it actively promotes the use of Dependency Injection while still employing Delegation, in my view it is somewhat overkill, at least in this case in particular.

Reusing Implementation – a Walk-through of Inheritance, Composition, and Delegation

Reusing Implementation – a Walk-through of Inheritance, Composition, and Delegation Posted on 18-04-2016  It shouldn’t be breaking news that the first code reuse approach I plan to put in the spotlight first is the most overused and misused of all, Inheritance. 4.5/10 259

Comment:

To comment you must be logged in members.

Files with category

  • How to Picking the Brains of Your Customers with Microsoft’s Text Analytics

    View: 3806    Download: 0   Comment: 0   Author: none  

    How to Picking the Brains of Your Customers with Microsoft’s Text Analytics

    Category: Php&mySql
    Fields: Other

    2.5/2 review
    With the explosion of machine learning services in recent years, it has become easier than ever for developers to create “smart apps”. In this article, I’ll introduce you to Microsoft’s offering for providing machine-learning capabilities to apps.

  • How to MySqli Tutorial PHP MySqli Extension

    View: 320    Download: 0   Comment: 0   Author: none  

    How to MySqli Tutorial PHP MySqli Extension

    Category: Php&mySql
    Fields: Other

    0/0 review
    PHP provides three api to connect mysql Database.

  • Make Laravel Artisan Commands

    View: 294    Download: 0   Comment: 0   Author: none  

    Make Laravel Artisan Commands

    Category: Php&mySql
    Fields: Other

    0/0 review
    Artisan is the command line tool used in Laravel framework. It offers a bunch of useful command that can help you develop application quickly. Apart from Artisan available commands, you can create your own custom commands to improve your workflow.

  • Check if a Number is a Power of 2

    View: 278    Download: 0   Comment: 0   Author: none  

    Check if a Number is a Power of 2

    Category: Php&mySql
    Fields: Other

    2.25/2 review
    How to check if a number is a power of 2. To understand this question, let’s take some example.

  • Concatenate columns in MySql

    View: 341    Download: 0   Comment: 0   Author: none  

    Concatenate columns in MySql

    Category: Php&mySql
    Fields: Other

    0/1 review
    Artisan is the command line tool used in Laravel framework. It offers a bunch of useful command that can help you develop application quickly. Apart from Artisan available commands, you can create your own custom commands to improve your workflow

  • How to Query NULL Value in MySql

    View: 269    Download: 0   Comment: 0   Author: none  

    How to Query NULL Value in MySql

    Category: Php&mySql
    Fields: Other

    5/1 review
    Misunderstanding NULL is common mistake beginners do while writing MySql query. While quering in MySql they compare column name with NULL. In MySql NULL is nothing or in simple word it isUnknown Value so if you use comparison operator for NULL values...

  • How to Abstract Class in PHP

    View: 308    Download: 0   Comment: 0   Author: none  

    How to Abstract Class in PHP

    Category: Php&mySql
    Fields: Other

    0/0 review
    What is an abstract class in PHP and when to use an abstract class in your application. In this tutorial, we’ll learn about abstract class and their implementation.

  • Use Enums in Rails for Mapped Values

    View: 283    Download: 0   Comment: 0   Author: none  

    Use Enums in Rails for Mapped Values

    Category: Php&mySql
    Fields: Other

    2.5/2 review
    When I worked in a call center, we used to mark cases with different statuses. This allowed upper management to get a handle on where cases stood, what the bottlenecks were and flow of calls. Thankfully it has been a long time since I worked in a...

 
Newsletter Email

File suggestion for you

File top downloads

logo codetitle
Codetitle.com - library source code to share, download the file to the community
Copyright © 2015. All rights reserved. codetitle.com Develope by Vinagon .Ltd