PHP Single Responsibility Principle of Five Object Oriented Principles of SRP Detailed Explanation

  • 2021-09-20 19:46:08
  • OfStack

This paper illustrates the single responsibility principle (SRP), which is one of the five object-oriented principles of PHP. Share it for your reference, as follows:

Single 1 duty principle (Single Pesponsibility Principle, SRP)

Single 1 responsibilities have two meanings: 1 is to avoid the same responsibilities being scattered among different classes, and the other is to avoid one class taking on too many responsibilities

Why comply with SRP?

(1) The coupling between classes can be reduced

If the coupling between classes is reduced, when the requirements change, only one class is modified, thus isolating the changes; If a class has multiple different responsibilities, they are coupled in one, and when one responsibility changes, it may affect other responsibilities.

(2) Improve the reusability of classes

Modifying a computer is much easier than repairing a TV set. The main reason is that the coupling between various components of TV sets is too high, while computers are different. The memory, hard disk, sound card, network card, keyboard lights and other components of computers can be easily disassembled and assembled separately. If a part is broken, just replace it with a new one. The above example shows the advantages of single 1 responsibility. Due to the use of single 1 responsibilities, 'components' can be easily'disassembled 'and'assembled'.

Non-compliance with SRP will affect the reusability of classes. When only one responsibility of this class is needed, it is difficult to separate it from other responsibilities because it is coupled in one.

Is there any application of SRP compliance in actual code development? Yes. Take the data persistence layer as an example. The so-called data persistence layer mainly refers to database operation, and of course, it also includes cache management. At this time, it is necessary for the data persistence layer to support multiple databases. What should be done? Define multiple database operation classes? The idea is very close, and one more step is to use the factory mode.

Factory mode (Faction) allows you to instantiate objects during code execution. It is called factory pattern because it is responsible for'production objects'. Taking the database as an example, what the factory needs is to generate different instantiated objects according to different parameters. The simplest factory is to instantiate the object according to the type name passed in. If MySQL is passed in, it calls MySQL class and instantiates it. If SQLite is passed, it calls SQLite class and instantiates it. It can even handle TXT, Execl and other'class databases'.

The factory class is one such class, which is only responsible for producing objects, not for the specific contents of objects.

Here's an example

Define the interface of 1 adapter


interface Db_Adpater
{
  /**
   *  Database connection 
   * @param $config  Database configuration 
   * @return mixed resource
   */
  public function connect($config);
  /**
   *  Execute a database query 
   * @param $query  Of the database query SQL String 
   * @param $handle  Connection object 
   * @return mixed
   */
  public function query($query,$handle);
}

Define an MySQL database operation class that implements DB_Adpater interface


class Db_Adapter_Mysql implements Db_Adpater
{
  private $_dbLink;  // Database connection string identification 
  /**
   *  Database connection function 
   * @param $config  Database configuration 
   * @return resource
   * @throws Db_Exception
   */
  public function connect($config)
  {
    if($this->_dbLink = @mysql_connect($config->host . (empty($config->port) ? '' : ':' . $config->prot) ,$config->user, $config->password, true))
    {
      if(@mysql_select_db($config->database, $this->_dbLink))
      {
        if($config->charset)
        {
          mysql_query("SET NAME '{$config->charset}'", $this->_dbLink);
        }
        return $this->_dbLink;
      }
    }
    throw new Db_Exception(@mysql_error($this->_dbLink));
  }
  /**
   *  Execute a database query 
   * @param $query  Database query SQL String 
   * @param $handle  Connection object 
   * @return resource
   */
  public function query($query,$handle)
  {
    if($resource = @mysql_query($query,$handle))
      return $resource;
  }
}

Defines an SQLite database operation class that implements the DB_Adpater interface


class Db_Adapter_sqlite implements Db_Adpater
{
  private $_dbLink;  // Database connection string identification 
  public function connect($config)
  {
    if($this->_dbLink = sqlite_open($config->file, 0666, $error))
    {
      return $this->_dbLink;
    }
    throw new Db_Exception($error);
  }
  public function query($query, $handle)
  {
    if($resource = @sqlite_query($query,$handle))
    {
      return $resource;
    }
  }
}

Now, if you need a database operation method, you only need to define a factory class, and generate different classes according to the incoming


class sqlFactory
{
  public static function factory($type)
  {
    if(include_once 'Drivers/' . $type . '.php')
    {
      $classname = 'Db_Adapter_'.$type;
      return new $classname;
    }
    else
      throw new Exception('Driver not found');
  }
}

Called, you can write


$db = sqlFactory::factory('MySQL');
$db = sqlFactory::factory('SQLite');

We create a database connection to this program alone, the program CURD does not need to care about any database, as long as the corresponding method can be used in accordance with the specification.

The factory method frees concrete objects from relying on concrete classes, but abstracting them.

The command pattern in design pattern is also the embodiment of SRP, and the command pattern separates the responsibilities of "command requester" and "command implementer". To give a well-understood example, when you go to a restaurant to order food, there are three roles in the restaurant: customer, waiter and chef. As a customer, you should list the menu and pass it on to the waiter, who will inform the chef to realize it. As a waiter, you only need to call the method of preparing meals (shouting "Time to stir-fry" to the chef), and when the chef hears the request to stir-fry, he immediately cooks. Here, the request and implementation of the command are decoupled.

To simulate this process, first define the role of chef, and the chef will actually cook and cook soup.

Here's an example


/**
 *  Chefs, order recipients and executors 
 * Class cook
 */
class cook
{
  public function meal()
  {
    echo ' Scrambled egg with tomato ',PHP_EOL;
  }
  public function drink()
  {
    echo ' Porphyra and Egg Flower Soup ',PHP_EOL;
  }
  public function ok()
  {
    echo ' Over ',PHP_EOL;
  }
}
// Then there is the command interface 
interface Command
{
  public function execute();
}

It's the waiter's turn to appear, and the waiter is the transmitter of the order. Usually, when you go to a restaurant to eat, you call the waiter, not the chef directly. Generally, it is called "Waiter, give me a plate of tomatoes and fried tomatoes". Therefore, the waiter is the command communication between the customer and the chef.


class MealCommand implements Command
{
  private $cook;
  // Bind command recipient 
  public function __construct(cook $cook)
  {
    $this->cook = $cook;
  }
  public function execute()
  {
    $this->cook->meal();// Pass the news to the chef and let the chef cook, the same below 
  }
}
class DrinkCommand implements Command
{
  private $cook;
  // Bind command recipient 
  public function __construct(cook $cook)
  {
    $this->cook = $cook;
  }
  public function execute()
  {
    $this->cook->drink();
  }
}

Now customers can call the waiter according to the menu


class cookControl
{
  private $mealcommand;
  private $drinkcommand;
  // Bind the command sender to the command receiver 
  public function addCommand(Command $mealcommand, Command $drinkcommand)
  {
    $this->mealcommand = $mealcommand;
    $this->drinkcommand = $drinkcommand;
  }
  public function callmeal()
  {
    $this->mealcommand->execute();
  }
  public function calldrink()
  {
    $this->drinkcommand->execute();
  }
}

Ok, now finish the whole process


$control = new cookControl;
$cook = new cook;
$mealcommand = new MealCommand($cook);
$drinkcommand = new DrinkCommand($cook);
$control->addCommand($mealcommand,$drinkcommand);
$control->callmeal();
$control->calldrink();

It can be seen from the above examples that the original design pattern is not a pure theoretical thing, but comes from real life, and even ordinary restaurant owners know the seemingly profound knowledge of design pattern. In fact, the optimization of process in economic and management activities is the exploration and practice of various design patterns. Therefore, design patterns are not patents in computer programming. In fact, the origin of design pattern is not computer, but architecture.

In terms of design patterns, not only these two embody SRP, but also others (such as proxy patterns) embody SRP. SRP is not only meaningful for class design, but also meaningful for system architecture design with modules and subsystems as units.

Modules and subsystems should have only one reason for their changes. For example, the separation of each layer advocated by MVC is the application of SRP in the overall system design.

SRP is one of the simplest principles and one of the hardest to do well. We will naturally link our responsibilities to one. Finding and separating these responsibilities is what software design needs to achieve

1 Some simple applications follow the following practices:

According to the business process, the business objects are refined. If the link of the business process is too complex, the business object is separated into multiple single 1 business objects. When the business chain is standardized, the internal situation of the business object is processed one step further, and the first standardization is regarded as the highest level abstraction, the second as the second level abstraction, and so on, until the "appropriate" design level

The classification of duties needs attention. There are business responsibilities and abstract responsibilities that are separated from business. It is a progressive process from recognizing business to abstract algorithm. Just like the responsibilities of customers, waiters and chefs in the command mode, as a boss (i.e., designer), you need to plan your respective responsibilities, that is, to prevent overstepping and shirking each other.

For more readers interested in PHP related content, please check the topics on this site: "Introduction to php Object-Oriented Programming", "Encyclopedia of PHP Array (Array) Operation Skills", "Introduction to PHP Basic Syntax", "Summary of PHP Operation and Operator Usage", "Summary of php String (string) Usage", "Introduction to php+mysql Database Operation Skills" and "Summary of php Common Database Operation Skills"

I hope this article is helpful to everyone's PHP programming.


Related articles: