Five common PHP design patterns

Source: Internet
Author: User
Five common PHP Design patterns the book introduces Design patterns into the software community by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides Design (commonly known as the "four-person gang "). The core concept behind the design pattern is very simple. After years of software development practices, Gamma and others have discovered some patterns of fixed design. just like architects designing houses and buildings, they can develop templates for bathroom locations or kitchen structures. Using these templates or design patterns means faster building design. The same concept applies to software.

The design pattern not only represents a useful way to develop robust software faster, but also provides a method to encapsulate large concepts in friendly terms. For example, you can say that you are writing a message transmission system that provides loose coupling, or you are writing a mode named observer.

It is very difficult to use small examples to demonstrate the value of the model. This is often a little practical, because the model actually plays a role in large code libraries. This article does not show large applications, so you need to think about how to apply sample principles in your own large applications ?? Instead of the code demonstrated in this article. This does not mean that you should not use the mode in a small application. Many good applications are developed from small applications to large applications, so there is no reason not to base on such solid coding practices.

Now that you know the design patterns and their usefulness, let's take a look at the five common patterns of PHP V5.

Factory model

Many design patterns encourage loose coupling in the design patterns book. To understand this concept, we 'd better talk about the hard work of many developers engaged in large-scale systems. When changing a code snippet, a problem occurs. what is the other part of the system ?? Cascade damage may also occur in the unrelated parts you once thought.

This problem lies in tight coupling. Functions and classes in a certain part of the system depend heavily on the behavior and structure of functions and classes in other parts of the system. You need a set of modes to enable these classes to communicate with each other, but do not want to closely bind them together to avoid interlocking.

In large systems, many codes depend on a few key classes. It may be difficult to change these classes. For example, assume that you have a User class to read from a file. You want to change it to other classes read from the database, but all code references the original class read from the file. At this time, it is very convenient to use the factory model.

Factory mode is a type that provides methods for creating objects for you. You can use the factory class to create objects instead of using new directly. In this way, if you want to change the type of the created object, you only need to change the factory. All codes used in the factory are automatically changed.

Listing 1 shows an indication column of the factory class. The server side of the equation consists of a database and a set of PHP pages that allow you to add feedback, request feedback lists, and obtain articles related to specific feedback.

Listing 1. Factory1.php

interface IUser{  function getName();}class User implements IUser{  public function __construct( $id ) { }  public function getName()  {    return "Jack";  }}class UserFactory{  public static function Create( $id )  {    return new User( $id );  }}$uo = UserFactory::Create( 1 );echo( $uo->getName()."\n" );

  

The IUser interface defines what operations a user object should perform. The implementation of IUser is called User, and the UserFactory class creates an IUser object. This relationship can be expressed in UML in figure 1.

Figure 1. factory class and related IUser interface and user class

If you use the php interpreter to run this code on the command line, the following result is displayed:

% php factory1.php Jack%

  

The test code will request the User object to the factory and output the result of the getName method.

There is a variation in the factory model that uses the Factory method. Class. This method is useful when you create an object of this type. For example, suppose you need to create an object first and then set many attributes. The factory mode of this version encapsulates the process in a single location, so that you do not need to copy complicated initialization code or paste the copied code everywhere in the code base.

Listing 2 shows an example of using the factory method.

Listing 2. Factory2.php

interface IUser{  function getName();}class User implements IUser{  public static function Load( $id )   {        return new User( $id );  }  public static function Create( )   {        return new User( null );  }  public function __construct( $id ) { }  public function getName()  {    return "Jack";  }}$uo = User::Load( 1 );echo( $uo->getName()."\n" );

  

This code is much simpler. It only has one IUser interface and one User class that implements this interface. The User class has two static methods for creating objects. This link can be expressed in UML in figure 2.

Figure 2. IUser interface and user class with factory method

The result of running the script in the command line is the same as that in listing 1, as shown below:

% php factory2.php Jack%

  

As mentioned above, sometimes such models seem to be a little useful in a small environment. However, it is best to learn this solid coding format to apply it to any scale of projects.

Single element mode

Some application resources are exclusive because there is only one resource of this type. For example, the connection from a database handle to a database is exclusive. You want to share the database handle in the application, because it is an overhead when you keep the connection open or closed, especially when you get a single page.

The single-element mode can meet this requirement. If an application contains only one object each time, the object is a Singleton ). The code in listing 3 shows a single database connection element in PHP V5.

Listing 3. Singleton. php

require_once("DB.php");class DatabaseConnection{  public static function get()  {    static $db = null;    if ( $db == null )      $db = new DatabaseConnection();    return $db;  }  private $_handle = null;  private function __construct()  {    $dsn = 'mysql://root:password@localhost/photos';    $this->_handle =& DB::Connect( $dsn, array() );  }    public function handle()  {    return $this->_handle;  }}print( "Handle = ".DatabaseConnection::get()->handle()."\n" );print( "Handle = ".DatabaseConnection::get()->handle()."\n" );

  

This code displays a single class named DatabaseConnection. You cannot create your own DatabaseConnection because the constructor is dedicated. However, with the static get method, you can obtain only one DatabaseConnection object. This code is shown in UML 3.

Figure 3. database connection ticket elements

In the two calls, the database handle returned by the handle method is the same, which is the best proof. You can run the code in the command line to observe this point.

% php singleton.php Handle = Object id #3Handle = Object id #3%

  

The two handles returned are the same object. If you use a single database connection element in the entire application, you can reuse the same handle anywhere.

You can use global variables to store database handles. However, this method is only applicable to small applications. In large applications, avoid using global variables and use objects and methods to access resources.

Observer Mode

The Observer Mode provides another way to avoid close coupling between components. This mode is very simple: an object becomes observability by adding a method (this method allows another object, that is, the Observer registers itself. When an observed object changes, the message is sent to the registered observer. The operations performed by these observers using this information are irrelevant to the observed objects. The result is that objects can communicate with each other without understanding the cause.

A simple example is the user list in the system. The code in listing 4 shows a user list. when a user is added, it sends a message. When a user is added, the list can be observed by the log observer who sends the message.

Listing 4. Observer. php

interface IObserver{  function onChanged( $sender, $args );}interface IObservable{  function addObserver( $observer );}class UserList implements IObservable{  private $_observers = array();  public function addCustomer( $name )  {    foreach( $this->_observers as $obs )      $obs->onChanged( $this, $name );  }  public function addObserver( $observer )  {    $this->_observers []= $observer;  }}class UserListLogger implements IObserver{  public function onChanged( $sender, $args )  {    echo( "'$args' added to user list\n" );  }}$ul = new UserList();$ul->addObserver( new UserListLogger() );$ul->addCustomer( "Jack" );

  

This code defines four elements: two interfaces and two classes. The IObservable interface defines the objects that can be observed. UserList implements this interface to register itself as an observed object. The IObserver list defines how to become an observer, and UserListLogger implements the IObserver interface. The elements are shown in UML in figure 4.

Figure 4. observed user list and user list event log programs

If you run it in the command line, you will see the following output:

% php observer.php 'Jack' added to user list%

  

Test code to create a UserList and add the UserListLogger observer to it. Then add a consumer and notify UserListLogger of this change.

It is critical to realize that the UserList does not know what operations the log program will perform. One or more listeners may execute other operations. For example, you may have an observer who sends messages to a new user. You are welcome to use this system. The value of this method is that UserList ignores all objects dependent on it. it focuses on maintaining the user list and sending messages when the list is changed.

This mode is not limited to objects in memory. It is the basis for database-driven message query systems used in large applications.

Command chain mode

The command chain mode sends messages, commands, and requests based on loosely coupled topics, or sends arbitrary content through a set of handlers. Each handler determines whether it can process the request. If yes, the request is processed and the process stops. You can add or remove a handler for the system without affecting other handlers. Listing 5 shows an example of this mode.

Listing 5. Chain. php

interface ICommand{  function onCommand( $name, $args );}class CommandChain{  private $_commands = array();  public function addCommand( $cmd )  {    $this->_commands []= $cmd;  }  public function runCommand( $name, $args )  {    foreach( $this->_commands as $cmd )    {      if ( $cmd->onCommand( $name, $args ) )        return;    }  }}class UserCommand implements ICommand{  public function onCommand( $name, $args )  {    if ( $name != 'addUser' ) return false;    echo( "UserCommand handling 'addUser'\n" );    return true;  }}class MailCommand implements ICommand{  public function onCommand( $name, $args )  {    if ( $name != 'mail' ) return false;    echo( "MailCommand handling 'mail'\n" );    return true;  }}$cc = new CommandChain();$cc->addCommand( new UserCommand() );$cc->addCommand( new MailCommand() );$cc->runCommand( 'addUser', null );$cc->runCommand( 'mail', null );

  

This code defines the CommandChain class that maintains the list of ICommand objects. Can both classes implement the ICommand interface ?? One responds to the email request and the other responds to the added user. Figure 5 shows the UML.

Figure 5. command chain and related commands

If you run a script containing some test code, the following output is displayed:

% php chain.php UserCommand handling 'addUser'MailCommand handling 'mail'%

  

The code first creates a CommandChain object and adds instances of two command objects to it. Then run two commands to check who has responded to these commands. If the command name matches UserCommand or MailCommand, the code fails without any operation.

When creating a scalable architecture for request processing, the command chain mode is very valuable and can solve many problems.

Rule mode

The last design pattern we talk about is the strategy pattern. In this mode, algorithms are extracted from complex classes and can be easily replaced. For example, if you want to change the page arrangement method in the search engine, the policy mode is a good choice. Think about the search engine ?? Part of the page is traversed, part is arranged on each page, and the other part is sorted based on the arranged results. In a complex example, these parts are in the same class. By using the policy mode, you can place the arranged parts into another class to change the page arrangement method without affecting the rest of the search engine code.

As a simple example, listing 6 shows a user list class, which provides a method for finding a group of users based on a set of plug-and-play policies.

Listing 6. Strategy. php

interface IStrategy{  function filter( $record );}class FindAfterStrategy implements IStrategy{  private $_name;  public function __construct( $name )  {    $this->_name = $name;  }  public function filter( $record )  {    return strcmp( $this->_name, $record ) <= 0;  }}class RandomStrategy implements IStrategy{  public function filter( $record )  {    return rand( 0, 1 ) >= 0.5;  }}class UserList{  private $_list = array();  public function __construct( $names )  {    if ( $names != null )    {      foreach( $names as $name )      {        $this->_list []= $name;      }    }  }  public function add( $name )  {    $this->_list []= $name;  }  public function find( $filter )  {    $recs = array();    foreach( $this->_list as $user )    {      if ( $filter->filter( $user ) )        $recs []= $user;    }    return $recs;  }}$ul = new UserList( array( "Andy", "Jack", "Lori", "Megan" ) );$f1 = $ul->find( new FindAfterStrategy( "J" ) );print_r( $f1 );$f2 = $ul->find( new RandomStrategy() );print_r( $f2 );

  

This code is shown in UML 6.

Figure 6. user list and user selection policy

The UserList class is a package for packaging name arrays. It implements the find method. this method selects a subset of these names using one of several policies. These policies are defined by the IStrategy interface, which has two implementations: one randomly selects the user and the other selects all the subsequent names based on the specified name. When you run the test code, the following output is displayed:

% php strategy.php Array(    [0] => Jack    [1] => Lori    [2] => Megan)Array(    [0] => Andy    [1] => Megan)%

  

The test code runs the same user list for two policies and displays the results. In the first case, the policy looks for any name after J, so you will get Jack, Lori, and Megan. The second policy selects a random name and produces different results each time. In this case, the result is Andy and Megan.

The rule mode is very suitable for complex data management systems or data processing systems. The two require high flexibility in data filtering, search, or processing methods.

Conclusion

This article only describes several of the most common design patterns used in PHP applications. The book on design patterns demonstrates more design patterns. Do not give up because the architecture is mysterious. Pattern is a wonderful concept, applicable to any programming language, any skill level.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.