Design
Design patterns are just for the Java architect--at least you've probably always thought so. In fact, design patterns are very useful for everyone. If these tools are not patents for "architecture astronauts", what are they? Why are they very useful in the application? This article explains these problems. Php
Design pattern a book introduces design patterns into the software community, the authors of which are Erich Gamma, Richard Helm, Ralph Johnson and John vlissides (commonly known as "gang"). The core concept behind the design pattern described is very simple. After years of software development practice, Gamma and others have discovered certain patterns with fixed designs, just as architects design houses and buildings to develop templates for the location of the bathroom or the way the kitchen is constructed. Using these templates, or design patterns, means that better buildings can be designed faster. The same concept applies to software.
Design patterns not only represent a useful way to develop robust software faster, but also provide a way to encapsulate large ideas in friendly terms. For example, you can say that you are writing a loosely coupled messaging system, or you are writing a pattern named Observer.
It is very difficult to demonstrate the value of a schema with a smaller sample. This is often a bit of a overkill, because the pattern actually works in a large code base. This article does not show large applications, so you need to think about how to apply the principle of the example in your own large application-not the code itself, as demonstrated in this article. This is not to say that you should not use patterns in small applications. Many good applications start with small applications and evolve into large applications, so there is no reason not to build on such solid coding practices.
Now that you understand the design patterns and their usefulness, let's look at the five common patterns of PHP V5.
Factory mode
Originally in design pattern book, many design patterns encourage the use of loose coupling. To understand this concept, let's talk a little bit about the hard work of many developers working on large systems. When you change a piece of code, there is a problem, and cascading damage may occur in other parts of the system that you thought were completely unrelated.
The problem is tight coupling. Functions and classes in one part of a system are heavily dependent on the behavior and structure of functions and classes in other parts of the system. You need a set of patterns that enable these classes to communicate with each other, but do not want them to be tightly bound together to avoid interlocking.
In large systems, many of the code relies on a few key classes. There may be difficulties when you need to change these classes. For example, suppose you have a User class that is read from a file. You want to change it to another class that is read from the database, but all code references the original class read from the file. At this point, it is convenient to use the Factory mode.
A factory pattern is a class that has some methods for creating objects for you. You can use the factory class to create objects without using new directly. This way, if you want to change the type of object you are creating, simply change the factory. All code that uses the factory is automatically changed.
Listing 1 shows an example of the factory class. The server side of the equation consists of two parts: a database and a set of PHP pages that allow you to add feedback, request feedback lists, and get articles related to specific feedback.
Listing 1. factory1.php
<?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 action the user object should perform. The Iuser implementation, called the User,userfactory factory class, creates the Iuser object. This relationship can be represented by the UML in Figure 1.
Figure 1. Factory classes and their associated Iuser interfaces and user classes
If you run this code on the command line using the PHP interpreter, you will get the following result:
% PHP factory1.php
Jack
%
The test code requests the User object to the factory and outputs the results of the GetName method.
There is a variant of the factory pattern using the factory method. class to construct objects of that type in the public static methods in the This method is useful if you are creating objects of this type that are important. For example, suppose you need to create an object first, and then set many properties. This version of the factory pattern encapsulates the process in a single location so that you do not have to copy the complex initialization code, and you do not have to paste the copied code all over the code base.
Listing 2 shows an example of using a factory method.
Listing 2. factory2.php
<?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 has only one interface Iuser and one User class that implements this interface. The User class has two static methods for creating objects. This relationship can be represented in UML in Figure 2.
Figure 2. Iuser interface and user class with factory method
Running the script on the command line produces the same result as listing 1, as follows:
% PHP factory2.php
Jack
%
As noted above, sometimes such models appear to be somewhat overqualified in smaller environments. However, it is a good idea to learn this solid coding form to apply to projects of any size.
Single element mode
Some application resources are exclusive because there is only one resource of this type. For example, a connection through a database handle to a database is exclusive. You want to share the database handle in your application because it is an overhead when the connection is turned on or off, especially in the process of getting a single page.
A single element pattern can satisfy this requirement. If the application contains and contains only one object at a time, the object is a cell element (Singleton). The code in Listing 3 shows a single database connection element in the PHP V5.
Listing 3. singleton.php
<?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 constructors are private. However, using the static Get method, you can obtain and obtain only one DatabaseConnection object. The UML for this code is shown in Figure 3.
Figure 3. Database connection single Element
The handle method returns the same database handle between two calls, which is the best proof. You can see this by running code on the command line.
% PHP singleton.php
Handle = Object ID #3
Handle = Object ID #3
%
The two handles returned are the same object. If you use database connection single elements throughout your application, you can reuse the same handle anywhere.
You can use global variables to store database handles, but this method applies only to smaller applications. In larger applications, you should avoid using global variables and access resources using objects and methods.
Observer mode
The Observer pattern gives you another way to avoid tight coupling between components. The pattern is simple: an object makes itself observable by adding a method that allows another object, the observer, to register itself. When an observable object changes, it sends the message to the registered observer. The actions that these observers perform with this information are independent of the observable objects. The result is that objects can talk to each other without having to understand why.
A simple example is the list of users in the system. The code in Listing 4 shows a list of users that will send a message when they are added. When you add a user, the log viewer who sends the message can observe the list.
Listing 4. observer.php
<?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, and userlist implements the interface to register itself as observable. The IObserver list defines how you can become an observer, Userlistlogger implement the IObserver interface. These elements are shown in UML in Figure 4.
Figure 4. Observable list of users and user list event log programs
If you run it on the command line, you will see the following output:
% PHP observer.php
' Jack ' added to user list
%
The test code creates the UserList and adds the Userlistlogger observer to it. Then add a consumer and notify Userlistlogger of this change.
It is critical to recognize that userlist does not know what the log program is doing. There may be one or more listeners that perform other actions. For example, you might have an observer who sends a message to a new user, and you are welcome to use the system by a new user. The value of this approach is that userlist ignores all objects that depend on it, focusing on maintaining the list of users and sending messages when the list changes.
This mode is not limited to objects in memory. It is the basis for a database-driven message query system that is used in larger applications.
Command chain mode
The command chain pattern is based on loosely coupled topics, sending messages, commands, and requests, or sending arbitrary content through a set of handlers. Each handler will decide for itself whether it can handle the request. If it can, the request is processed and the process is stopped. You can add or remove handlers for your system without affecting other handlers. Listing 5 shows an example of this pattern.
Listing 5. chain.php
<?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 ')";
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 a list of ICommand objects. All two classes can implement the ICommand interface-one response to a request for a message, and the other to add a user. Figure 5 shows the UML.
Figure 5. Command chain and its related commands
If you run a script that contains some test code, you get the following output:
% PHP chain.php
UserCommand handling ' AddUser '
Mailcommand Handling ' mail '
%
The code first creates the Commandchain object and adds an instance of two command objects to it. Then run two commands to see who responded to these commands. If the name of the command matches UserCommand or Mailcommand, the code fails and no action occurs.
The command chain pattern is valuable when creating extensible schemas for processing requests, and can be used to solve many problems.
Policy mode
The last design pattern we're talking about is the policy pattern. In this pattern, the algorithm is extracted from the complex class and can be easily replaced. For example, if you want to change the way a page is arranged in a search engine, the policy mode is a good choice. Think about a few parts of the search engine--one that traverses the page, one part for each page, and the other based on the sorted results. In a complex example, these parts are in the same class. By using the policy pattern, you can place the arrangement part in another class to change the way the page is arranged without affecting the rest of the code for the search engine.
As a simpler example, listing 6 shows a user list class that provides a way to find a group of users based on a set of Plug and Play policies.
Listing 6. strategy.php
<?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 to 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"));
$f 1 = $ul->find (new Findafterstrategy ("J"));
Print_r ($f 1);
$f 2 = $ul->find (new Randomstrategy ());
Print_r ($f 2);
?>
Figure 6. List of users and policies for selecting users
The UserList class is a wrapper over the packaged name array. It implements the Find method, which utilizes one of several strategies to select a subset of these names. These policies are defined by the IStrategy interface, which has two implementations: one randomly selects the user, and the other selects all subsequent names based on the specified name. When you run the test code, you get the following output:
% 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 that is listed after J, so you'll get Jack, Lori, and Megan. The second policy picks the name randomly, each time producing a different result. In this case, the result is Andy and Megan.
Policy patterns are ideal for complex data management systems or data processing systems, which require greater flexibility in the way data is filtered, searched, or processed.
Conclusion
This article is just a few of the most common design patterns used in PHP applications. More design patterns are demonstrated in the design pattern book. Don't give up because of the mystery of architecture. Patterns are a wonderful idea that works for any programming language, any skill level.