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 class that is read from a file User
. 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 instead of using them directly new
. 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 "); ?>
|
IUser
interface defines what action the user object should perform. is IUser
called User
, the UserFactory
factory class creates the IUser
object. This relationship can be represented by the UML in Figure 1.
Fig. 1. Factory classes and their associated Iuser interfaces and user classes
If you php
run this code on the command line using an interpreter, you get the following result:
The test code will request the object from the factory User
and output getName
The result of the 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 {
{ return new User ($id); }
{ 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 class that implements this interface User
. 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:
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 DatabaseConnection
a single class named. You cannot create a self DatabaseConnection
because the constructor is private. But with get
a static method, you can get and get only one DatabaseConnection
object. The UML for this code is shown in Figure 3.
Figure 3. Database connection cell element
The best proof of this is that the handle
database handle returned by the method is the same between two calls. You can see this by running code on the command line.
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. An IObservable
interface defines an object that can be observed and UserList
implements the interface to register itself as observable. IObserver
The list defines how you can become an observer and implement an UserListLogger
IObserver
interface. These elements are shown in UML in Figure 4.
Figure 4. An observable list of users and user list event log programs
If you run it on the command line, you will see the following output:
' Jack ' added to user list %
|
Test the code creation UserList
and UserListLogger
Add the observer to it. Then add a consumer and notify you of this change UserListLogger
.
UserList
It is critical to realize that it is not known what the log program will do. 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 UserList
to ignore 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 ICommand
a class that maintains a list of objects CommandChain
. Two classes can implement an ICommand
interface--one to respond to a request for a message, and another to respond to an added 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:
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); ?>
|
The UML for this code is shown in Figure 6.
Figure 6. List of users and policies for selecting users
UserList
Class is a wrapper for the packaged name array. It implements a find
method that uses one of several strategies to select a subset of these names. These policies IStrategy
are defined by an interface that has two implementations: a randomly selected user, and the other selects all subsequent names based on the specified name. When you run the test code, you get the following output:
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 J
any name that is listed after it, 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.