php – Implementation of Abstract Factory, Factory Method and Adapter patterns

Question:

I read the following sentence:

AbstractFactory defines an interface for creating a family of related or dependent products without you having to explicitly specify the classes.

Consider the following adapter:

adapter.php

 namespace Teste\Db; use Teste\Db\Adapter\DbInterface; class Adapter { private $config = null; public function __construct(array $config) { $this->config = $config; } public function factory() { $db = $this->config['db']; $class = __NAMESPACE__ . '\Adapter\DbAdapter' . $db; return new $class($this->config); } }

Note that this class has the factory method that returns the instance of a new class according to the configuration file:

config.ini

 db = MySQL dbname = fixeads username = 'root' passwd = 'root' host = localhost debug = true

I used the Factory Method pattern to know which class should be used only at script execution time. Note that in the settings file there is a definition:

 db = MySQL

With that, the adapter will generate an instance of the DbAdapterMySQL class (actually the class is of type DbInterface , see below):

 <?php namespace Teste\Db\Adapter; use Teste\Util\Iterator\Collection; class DbAdapterMySQL extends \PDO implements DbInterface { public function __construct(array $config) { $dsn = "mysql:dbname={$config['dbname']};host={$config['host']}"; parent::__construct($dsn, $config['username'], $config['passwd']); $this->setAttribute(self::ATTR_DEFAULT_FETCH_MODE, self::FETCH_ASSOC); } public function insert($table, array $fields) { //inserir } public function select($table, $cols = '*', $where = []) { //selecionar } public function getFields($table) { //descrição dos campos } }

Note that the class implements the DbInterface interface:

 <?php namespace Teste\Db\Adapter; interface DbInterface { public function __construct(array $config); public function select($table, $cols = '*', $where = null); public function insert($table, array $fields); public function getFields($table); }

And to use everything, I do the following:

 $config = parse_ini_file(sprintf(__DIR__ . '%sconfig.ini', DIRECTORY_SEPARATOR)); $dbAdapter = new DbAdapter($config); Mapper::$defaultAdapter = $dbAdapter->factory();

Can I say that I used the Adapter , Factory Method and Abstract Factory patterns in the classes above?

  • The Adapter pattern because I used the DbAdapterMySQL class to build a compatible interface with the application, so when I change from MySQL to MSSQL I just have to create a new DbAdapterMSSQL class and implement its methods.
  • The Factory Method pattern because I used the Adapter class's factory method to return an instance of the class that should be used (at runtime) according to the project's settings.
  • And here is my question, can I say that I used the Abstract Factory pattern? Since I used the DbInterface interface to create a family of related products, which in this case is for DBMS manipulation?

If yes, then the Adapter class together with the DbInterface and DbAdapterMySQL classes are the implementation of the Abstract Factory pattern?

Answer:

Hi, I'm not a php expert, but I could understand your question well.

My first observation is that you are using the abstract factory , I don't actually see you using it, because as you mentioned:

Since I used the DbInterface interface to create a family of related products, which in this case is for DBMS manipulation

Here we can see that you are not providing the creation for an entire product family. In fact, you are only taking care of providing the instance of a single product, in this case instances for the database.

We could consider a family for example if you had something like:

<?php

 namespace Teste\Db\Adapter;

class Adapter
{
    private $config = null;

    public function __construct(array $config)
    {
       $this->config = $config;
    }

    public function factoryBancoRelacional()
    {
    }
    public function factoryBancoNaoRelacional()
    {
    }
}

Note the difference, you have a class responsible for returning different types of databases, which are incompatible with each other, but belong to the same Database Manager family, different from the previous model where you have a class that will always return one to you. instance of a single product type, a relational database.

With that in mind, I see that with the sum of these patterns you ended up in the Bridge structural pattern.

Why this vision of mine?

On the source making site, the definition of this standard is very clear. Below are some of the rules that define it:

Adapter makes things work after they're designed; Bridge makes them work before they are.

  • Decouple an abstraction from its implementation so that the two can vary independently.

  • Publish interface in an inheritance hierarchy, and bury implementation in its own inheritance hierarchy.

  • Beyond encapsulation, to insulation

And basically what you've done is leverage so much of Adapter , since you're structuring your application so that "incompatible" databases can be used from a single perspective in your code, when in Bridge , where your Adapter abstraction , which provides the factory for the database, can vary independently as much as the implementations of DbInterface that execute its commands in the base.

Hope this my vision can help you.

Scroll to Top