Maison >développement back-end >tutoriel php >Partager des modèles de conception PHP courants

Partager des modèles de conception PHP courants

小云云
小云云original
2018-03-09 17:23:381529parcourir

Le livre Design Patterns a présenté les modèles de conception à la communauté des logiciels. Les auteurs du livre sont Erich Gamma, Richard Helm, Ralph Johnson et John Vlissides Design (communément appelé le « Gang of Four »). Les concepts de base derrière les modèles de conception présentés sont très simples. Après des années de pratique du développement de logiciels, Gamma et d'autres ont découvert certains modèles avec des conceptions fixes, un peu comme les architectes conçoivent des maisons et des bâtiments, développant des modèles indiquant l'emplacement d'une salle de bains ou la manière dont une cuisine doit être construite. L’utilisation de ces modèles, ou modèles de conception, permet de concevoir plus rapidement de meilleurs bâtiments. Le même concept s'applique aux logiciels.

Les modèles de conception représentent non seulement un moyen utile de développer plus rapidement des logiciels robustes, mais ils fournissent également un moyen d'encapsuler de grandes idées en termes conviviaux. Par exemple, vous pourriez dire que vous écrivez un système de messagerie qui fournit un couplage lâche, ou vous pourriez dire que vous écrivez un modèle nommé Observer.

Démontrer la valeur des modèles avec des exemples plus petits est très difficile. Cela semble souvent exagéré, car les modèles fonctionnent en réalité dans de grandes bases de code. Cet article ne présente pas une application de grande envergure, vous devez donc réfléchir aux moyens d'appliquer les principes de l'exemple dans votre propre application de grande envergure, et non au code lui-même présenté dans cet article. Cela ne veut pas dire que vous ne devriez pas utiliser de modèles dans les petites applications. De nombreuses bonnes applications commencent comme de petites applications et évoluent vers de grandes applications. Il n'y a donc aucune raison de ne pas s'appuyer sur des pratiques de codage aussi solides.

Maintenant que vous connaissez les modèles de conception et leur utilité, examinons les cinq modèles couramment utilisés dans PHP V5.

Modèle d'usine

À l'origine dans le livre Design Patterns, de nombreux modèles de conception encouragent l'utilisation de couplages lâches. Pour comprendre ce concept, il est préférable de parler du parcours ardu que traversent de nombreux développeurs en travaillant sur de grands systèmes. Des problèmes surviennent lorsqu'un morceau de code est modifié et que le reste du système — Il est possible que des dommages en cascade se produisent dans des parties que vous pensiez autrefois totalement indépendantes.

Le problème est un couplage serré. Les fonctions et classes d'une partie du système dépendent fortement du comportement et de la structure des fonctions et des classes d'autres parties du système. Vous voulez un ensemble de modèles qui permettent à ces classes de communiquer entre elles, mais vous ne voulez pas les lier étroitement pour éviter les imbrications.

Dans les grands systèmes, une grande partie du code dépend de quelques classes clés. Des difficultés peuvent survenir lorsqu'il faut modifier ces classes. Par exemple, supposons que vous ayez une classe User qui lit un fichier. Vous souhaitez le remplacer par une classe différente qui lit à partir de la base de données. Cependant, tout votre code fait référence à la classe d'origine qui lit à partir du fichier. À ce stade, il sera très pratique d’utiliser le mode usine.

Factory pattern est une classe qui possède certaines méthodes qui créent des objets pour vous. Vous pouvez utiliser des classes d'usine pour créer des objets au lieu d'utiliser directement new. De cette façon, si vous souhaitez changer le type d’objet créé, il vous suffit de changer d’usine. Tout le code utilisant cette usine est automatiquement modifié.

La liste 1 montre un exemple de classe d'usine. Le côté serveur de l'équation se compose de deux parties : une base de données et un ensemble de pages PHP qui vous permettent d'ajouter des commentaires, de demander une liste de commentaires et d'obtenir des articles liés à un retour spécifique.

Liste 1. Factory1.ph

<?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" );
?>

L'interface IUser définit les opérations que l'objet utilisateur doit effectuer. L'implémentation de IUser est appelée User et la classe d'usine UserFactory crée des objets IUser. Cette relation peut être montrée dans la figure Représentation UML en 1.

Figure 1. Classe Factory et son interface IUser et classe d'utilisateurs associées

工厂类及其相关 IUser 接口和用户类

Si vous exécutez ce code sur la ligne de commande à l'aide de l'interpréteur php, vous obtenez les résultats suivants :

% php factory1.php

Jack

%

% php factory1.phpJack%


测试代码会向工厂请求 User 对象,并输出 getName 方法的结果。

有一种工厂模式的变体使用工厂方法。类中的这些公共静态方法构造该类型的对象。如果创建此类型的对象非常重要,此方法非常有用。例如,假设您需要先创建对象,然后设置许多属性。此版本的工厂模式会将该进程封装在单个位置中,这样,不用复制复杂的初始化代码,也不必将复制好的代码在在代码库中到处粘贴。

清单 2 显示使用工厂方法的一个示例。

清单 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" );
?>

这段代码要简单得多。它仅有一个接口 IUser 和一个实现此接口的 User 类。User 类有两个创建对象的静态方法。此关系可用图 2 中的 UML 表示。

图 2. IUser 接口和带有工厂方法的 user 类

IUser 接口和带有工厂方法的用户类

在命令行中运行脚本产生的结果与清单 1 的结果相同,如下所示:

1

2

3

%
 php factory2.php
Jack
%


如上所述,有时此类模式在规模较小的环境中似乎有些大材小用。不过,最好还是学习这种扎实的编码形式,以便应用于任意规模的项目中。

单元素模式

某些应用程序资源是独占的,因为有且只有一个此类型的资源。例如,通过数据库句柄到数据库的连接是独占的。您希望在应用程序中共享数据库句柄,因为在保持连接打开或关闭时,它是一种开销,在获取单个页面的过程中更是如此。

单元素模式可以满足此要求。如果应用程序每次包含且仅包含一个对象,那么这个对象就是一个单元素(Singleton)。清单 3 中的代码显示了 PHP V5 中的一个Partager des modèles de conception PHP courants。

清单 3. Singleton.php

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

此代码显示名为 DatabaseConnection 的单个类。您不能创建自已的 DatabaseConnection,因为构造函数是专用的。但使用静态 get 方法,您可以获得且仅获得一个 DatabaseConnection 对象。此代码的 UML 如图 3 所示。

图 3. Partager des modèles de conception PHP courants

Partager des modèles de conception PHP courants

在两次调用间,handle 方法返回的数据库句柄是相同的,这就是最好的证明。您可以在命令行中运行代码来观察这一点。


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

返回的两个句柄是同一对象。如果您在整个应用程序中使用Partager des modèles de conception PHP courants,那么就可以在任何地方重用同一句柄。

您可以使用全局变量存储数据库句柄,但是,该方法仅适用于较小的应用程序。在较大的应用程序中,应避免使用全局变量,并使用对象和方法访问资源。

观察者模式

观察者模式为您提供了避免组件之间紧密耦合的另一种方法。该模式非常简单:一个对象通过添加一个方法(该方法允许另一个对象,即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。

一个简单示例是系统中的用户列表。清单 4 中的代码显示一个用户列表,添加用户时,它将发送出一条消息。添加用户时,通过发送消息的日志观察者可以观察此列表。

清单 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(
 "&#39;$args&#39; added to user list\n" );
  }
}
 
$ul
 = new UserList();
$ul->addObserver(
 new UserListLogger() );
$ul->addCustomer(
 "Jack" );
?>

此代码定义四个元素:两个接口和两个类。IObservable 接口定义可以被观察的对象,UserList 实现该接口,以便将本身注册为可观察。IObserver 列表定义要通过怎样的方法才能成为观察者,UserListLogger 实现 IObserver 接口。图 4 的 UML 中展示了这些元素。

图 4. Partager des modèles de conception PHP courants

Partager des modèles de conception PHP courants

如果在命令行中运行它,您将看到以下输出:


%
 php observer.php
&#39;Jack&#39;
 added to user list
%

测试代码创建 UserList,并将 UserListLogger 观察者添加到其中。然后添加一个消费者,并将这一更改通知 UserListLogger。

认识到 UserList 不知道日志程序将执行什么操作很关键。可能存在一个或多个执行其他操作的侦听程序。例如,您可能有一个向新用户发送消息的观察者,欢迎新用户使用该系统。这种方法的价值在于 UserList 忽略所有依赖它的对象,它主要关注在列表更改时维护用户列表并发送消息这一工作。

此模式不限于内存中的对象。它是在较大的应用程序中使用的数据库驱动的消息查询系统的基础。

命令链模式

命令链 模式以松散耦合主题为基础,发送消息、命令和请求,或通过一组处理程序发送任意内容。每个处理程序都会自行判断自己能否处理请求。如果可以,该请求被处理,进程停止。您可以为系统添加或移除处理程序,而不影响其他处理程序。清单 5 显示了此模式的一个示例。

清单 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 != &#39;addUser&#39; ) return false;
    echo(
 "UserCommand handling &#39;addUser&#39;\n" );
    return
 true;
  }
}
 
class
 MailCommand implements ICommand
{
  public
 function onCommand( $name, $args )
  {
    if
 ( $name != &#39;mail&#39; ) return false;
    echo(
 "MailCommand handling &#39;mail&#39;\n" );
    return
 true;
  }
}
 
$cc
 = new CommandChain();
$cc->addCommand(
 new UserCommand() );
$cc->addCommand(
 new MailCommand() );
$cc->runCommand(
 &#39;addUser&#39;, null );
$cc->runCommand(
 &#39;mail&#39;, null );
?>

Ce code définit la classe CommandChain qui maintient une liste d'objets ICommand. Les deux classes peuvent implémenter l'interface ICommand - L'un répond aux demandes d'e-mails et l'autre répond aux ajouts d'utilisateurs. La figure 5 montre l'UML.

Figure 5. Chaîne de commandes et ses commandes associées

Partager des modèles de conception PHP courants

Si vous exécutez le script qui contient du code de test, vous obtiendrez le résultat suivant :



% php chain.php

UserCommand handling 'addUser'

MailCommand handling 'mail'

%

% php chain.phpCommande utilisateur gestion de 'addUser'MailCommand gestion du « courrier »%

代码首先创建 CommandChain 对象,并为它添加两个命令对象的实例。然后运行两个命令以查看谁对这些命令作出了响应。如果命令的名称匹配 UserCommand 或 MailCommand,则代码失败,不发生任何操作。

为处理请求而创建可扩展的架构时,命令链模式很有价值,使用它可以解决许多问题。

策略模式

我们讲述的最后一个设计模式是策略 模式。在此模式中,算法是从复杂类提取的,因而可以方便地替换。例如,如果要更改搜索引擎中排列页的方法,则策略模式是一个不错的选择。思考一下搜索引擎的几个部分 —— 一部分遍历页面,一部分对每页排列,另一部分基于排列的结果排序。在复杂的示例中,这些部分都在同一个类中。通过使用策略模式,您可将排列部分放入另一个类中,以便更改页排列的方式,而不影响搜索引擎的其余代码。

作为一个较简单的示例,清单 6 显示了一个用户列表类,它提供了一个根据一组即插即用的策略查找一组用户的方法。

清单 6. Strategy.php
<?phpinterface
 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 );?>

此代码的 UML 如图 6 所示。

图 6. Partager des modèles de conception PHP courants

Partager des modèles de conception PHP courants

UserList 类是打包名称数组的一个包装器。它实现 find 方法,该方法利用几个策略之一来选择这些名称的子集。这些策略由 IStrategy 接口定义,该接口有两个实现:一个随机选择用户,另一个根据指定名称选择其后的所有名称。运行测试代码时,将得到以下输出:

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

测试代码为两个策略运行同一用户列表,并显示结果。在第一种情况中,策略查找排列在 J 后的任何名称,所以您将得到 Jack、Lori 和 Megan。第二个策略随机选取名称,每次会产生不同的结果。在这种情况下,结果为 Andy 和 Megan。

策略模式非常适合复杂数据管理系统或数据处理系统,二者在数据筛选、搜索或处理的方式方面需要较高的灵活性。

结束语

本文介绍的仅仅是 PHP 应用程序中使用的几种最常见的设计模式。在设计模式 一书中演示了更多的设计模式。不要因架构的神秘性而放弃。模式是一种绝妙的理念,适用于任何编程语言、任何技能水平。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn