Cet article présente trois modèles de conception PHP couramment utilisés : le mode singleton, le mode usine et le mode observateur. Les amis dans le besoin peuvent s'y référer.
1. Tout d'abord, regardons le mode singleton
Le mode dit singleton consiste à garantir qu'il n'y a qu'une seule instance d'une certaine classe, et il s'instancie et le fournit à l'ensemble du système. Cette instance signifie qu'une seule instance de cette classe existera dans l'application.
Habituellement, le mode singleton est utilisé dans les instances qui autorisent uniquement l'accès à la base de données aux objets, empêchant ainsi l'ouverture de plusieurs connexions à la base de données. Le mode singleton est un modèle de conception courant dans les systèmes informatiques, les pools de threads, les caches, les objets de journal et les boîtes de dialogue. les boîtiers, les imprimantes, les opérations de base de données et les pilotes de carte graphique sont souvent conçus comme des singletons.
Une classe singleton doit inclure les points suivants :
Contrairement aux classes ordinaires, les classes singleton ne peuvent pas être instanciées directement, mais ne peuvent être instanciées que par elles-mêmes. Par conséquent, pour obtenir de tels effets restrictifs, le constructeur doit être marqué comme privé.
Pour qu'une classe singleton fonctionne sans être instanciée directement, une telle instance doit lui être fournie. Par conséquent, il est nécessaire que la classe singleton ait une variable membre statique privée qui peut enregistrer l'instance de la classe et une méthode statique publique correspondante qui peut accéder à l'instance.
En PHP, afin d'éviter que le clonage de l'objet de classe singleton ne brise la forme d'implémentation ci-dessus de la classe singleton, une méthode privée __clone() vide est généralement fournie pour la base. Bon, sans plus attendre, le résumé est le suivant
Le mode singleton possède les 3 caractéristiques suivantes :
1. Il ne peut y avoir qu'une seule instance, elle doit avoir un constructeur et elle doit être marquée privée
2. Vous devez créer cette instance vous-même et disposer d'une variable membre statique qui enregistre l'instance de la classe
3. Cette instance doit être fournie à d'autres objets, et il existe une méthode statique publique pour accéder à cette instance
Une classe singleton ne peut pas être instanciée directement dans d'autres classes, mais ne peut être instanciée que par elle-même. Il ne crée pas de copie de l'instance, mais renvoie une référence à l'instance stockée dans la classe singleton
Alors pourquoi utiliser le modèle PHP singleton ?
L'un des principaux scénarios d'application de PHP est le scénario dans lequel l'application traite la base de données. Dans une application, il y aura un grand nombre d'opérations de base de données pour le comportement de connexion du handle de base de données à la base de données. , l'utilisation du mode singleton peut éviter un grand nombre de nouvelles opérations. Parce que chaque nouvelle opération consomme des ressources système et mémoire.
Dans le développement précédent du projet, la situation avant d'utiliser le mode singleton était la suivante :
//初始化一个数据库句柄$db = new DB(...);//比如有个应用场景是添加一条评论信息$db->addComment();......//如果我们要在另一地方使用这个评论信息,这时要用到数据库句柄资源,可能会这么做......function comment() { $db = new DB(...); $db->getCommentInfo();......//可能有些朋友也许会说,可以直接使用global关键字! global $db;......
En effet, global peut également résoudre le problème. joue le rôle de modèle singleton, mais en POO, nous recommandons de rejeter cet encodage. Parce que global comporte des risques de sécurité (la nature non protégée des variables globales).
Les variables globales sont l'une des principales causes de BUG rencontrés par les programmeurs orientés objet. En effet, les variables globales lient la classe à un environnement spécifique, rompant ainsi l'encapsulation. Une classe qui s'appuie sur des variables globales ne peut pas être extraite d'une application et appliquée à une nouvelle application si la nouvelle application ne peut pas garantir que les mêmes variables globales sont définies depuis le début.
Pour être précis, le mode singleton est une amélioration des variables globales, qui empêche les variables globales qui stockent des instances uniques de polluer l'espace de noms. Vous ne pouvez pas écraser un singleton avec des données du mauvais type. Cette protection est particulièrement importante dans les versions de PHP qui ne prennent pas en charge les espaces de noms. Parce qu'en PHP, les conflits de noms sont détectés au moment de la compilation et entraînent l'arrêt du script.
Nous utilisons le modèle singleton pour améliorer l'exemple suivant :
class Single { private $name;//声明一个私有的实例变量 private function __construct(){//声明私有构造方法为了防止外部代码使用new来创建对象。 } static public $instance;//声明一个静态变量(保存在类中唯一的一个实例) static public function getinstance(){//声明一个getinstance()静态方法,用于检测是否有实例对象 if(!self::$instance) self::$instance = new self(); return self::$instance; } public function setname($n){ $this->name = $n; } public function getname(){ return $this->name; } }$oa = Single::getinstance();$ob = Single::getinstance();$oa->setname('hello php world');$ob->setname('good morning php');echo $oa->getname();//good morning phpecho $ob->getname();//good morning php
Avantages et inconvénients du modèle singleton :
Avantages :
1. Améliorer la conception du système
2 C'est une amélioration sur les variables globales
Inconvénients :
1. pour déboguer
2. Dépendances cachées
3. Impossible d'écraser un singleton avec un mauvais type de données
2. 🎜> Le modèle factory est une classe qui contient une méthode spécifiquement utilisée pour créer d'autres objets. La classe factory est cruciale dans la pratique de la programmation polymorphe. Elle permet le remplacement dynamique des classes, la modification des configurations, et rend généralement l'application. plus flexible et il est important que les développeurs PHP expérimentés maîtrisent le mode usine.
Le modèle d'usine est généralement utilisé pour renvoyer différentes classes conformes à des interfaces similaires. Une utilisation courante des usines consiste à créer des fournisseurs polymorphes, nous permettant de décider lesquels doivent être instanciés en fonction de la logique de l'application ou des paramètres de configuration. Une classe, par exemple, peut être étendue à l'aide d'un tel fournisseur pour utiliser le nouveau nom étendu sans qu'il soit nécessaire de refactoriser d'autres parties de l'application. Habituellement, le modèle de fabrique a une construction clé, qui est une méthode statique nommée Factory selon le principe général. Cependant, ce n'est qu'un principe. Cette méthode statique peut également être nommée arbitrairement. accepter les paramètres de toutes les données. Il doit s'agir de renvoyer un objet.具有为您创建对象的某些方法,这样就可以使用工厂类创建对象,工厂模式在于可以根据输入参数或者应用程序配置的不同来创建一种专门用来实现化并返回其它类的实例的类,而不直接使用new,这样如果想更改创建的对象类型,只需更改该工厂即可,
先举个示例吧:
<?phpclass Factory {//创建一个基本的工厂类 static public function fac($id){//创建一个返回对象实例的静态方法 if(1 == $id) return new A(); elseif(2==$id) return new B(); elseif(3==$id) return new C(); return new D(); } }interface FetchName {//创建一个接口 public function getname();//}class A implements FetchName{ private $name = "AAAAA"; public function getname(){ return $this->name; } }class C implements FetchName{ private $name = "CCCCC"; public function getname(){ return $this->name; } }class B implements FetchName{ private $name = "BBBBB"; public function getname(){ return $this->name; } }class D implements FetchName{ private $name = "DDDDD"; public function getname(){ return $this->name; } }$o = Factory::fac(6);//调用工厂类中的方法if($o instanceof FetchName){ echo $o->getname();//DDDDD}$p=Factory::fac(3);echo $p->getname();//CCCCC?>
个人意见,再说简单点吧,PHP工厂模式就是用一个工厂方法来替换掉直接new对象的操作,就是为方便扩展,方便使用,在新增实现基类中的类中方法时候,那么在工厂类中无需修改,传入参数可以直接使用,具体就是跳过工厂类修改,直接使用工厂类输出想要的结果。在传统习惯中,如果要生成一个类的话,在代码中直接new一个对象,比如:
class Database{ } $db = new Database();
下面介绍工厂模式的操作方法:
class Database{ } //创建一个工厂类class Factory { //创建一个静态方法 static function createDatabase(){ $db = new Database; return $db; } }
那么,当我们想创建一个数据库类的话,就可以使用这样的方法:
<?php $db = Factory::createDatabase();?>
简单工厂模式比直接new一个对象的好处是,比如Database这个类在很多php文件中都有使用到,当Database这个类发生了某些变更,比如修改了类名、或者一些参数发生了变化,那这时候如果你使用的是$db = new Database这种传统方法生成对象,那么在所有包含这种生成对象的php文件代码中都要进行修改。而使用工厂模式,只要在工厂方法或类里面进行修改即可。而且工厂模式是其他设计模式的基础。
对上面的简单工厂模式再进一步优化,比如:
利用工厂类生产对象:
<?phpclass Example { // The parameterized factory method public static function factory($type) { if (include_once 'Drivers/' . $type . '.php') { $classname = 'Driver_' . $type; return new $classname; } else { throw new Exception('Driver not found'); } } } // Load a MySQL Driver$mysql = Example::factory('MySQL'); // Load an SQLite Driver$sqlite = Example::factory('SQLite');?>
简单工厂模式又称静态工厂方法模式。从命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。
要理解工厂模式这个概念,让我们最好谈一下许多开发人员从事大型系统的艰苦历程。在更改一个代码片段时,就会发生问题,系统其他部分 —— 您曾认为完全不相关的部分中也有可能出现级联破坏。
该问题在于紧密耦合 。系统某个部分中的函数和类严重依赖于系统的其他部分中函数和类的行为和结构。您需要一组模式,使这些类能够相互通信,但不希望将它们紧密绑定在一起,以避免出现联锁。
在大型系统中,许多代码依赖于少数几个关键类。需要更改这些类时,可能会出现困难。例如,假设您有一个从文件读取的 User 类。您希望将其更改为从数据库读取的其他类,但是,所有的代码都引用从文件读取的原始类。这时候,使用工厂模式会很方便。
看下实例:
<?php interface IUser { function getName(); } class User implements IUser { public $id; public function __construct( $id ) { } public function getName() { return "Fantasy"; } }?>
传统方法使用 User 类,一般都是这样:
<?php //在页面1$obj = new User(1); //在页面2$obj2 = new User(2); //在页面3$obj3 = new User(3);.... ?>
这时候,由于新的需求,使得User类要新增个参数或者User类名称发生变化,User 类代码发生变动,即:
<?phpclass User implements IUser { public $id,$pre; public function __construct( $id , $pre = '') {...} public function getName() { return $this->pre."Fantasy"; } }?>
接着,恐怖的事情发生了,假设之前有 100 个页面引用了之前的 User 类,那么这 100 个页面都要发生相应的改动:
//在页面1$obj = new User(1,'aaa'); //在页面2$obj = new User(2,'aaa'); //在页面3$obj = new User(3,'aaa');...
本来是一个小小的改动,但因紧密耦合的原因使得改动大吐血。而使用工厂模式则可以避免发生这种情况:
//User类为变动前class UserFactory { public static function Create( $id ) { return new User( $id ); } } //页面1$uo1 = UserFactory::Create( 1 ); //页面2$uo12 = UserFactory::Create( 2 );....
这时候需求变动,User 类也发生变动:
<?phpclass User implements IUser { public $id,$pre; public function __construct( $id , $pre = '') {...} public function getName() { return $this->pre."Jack"; } }?>
但是,我们不再需要去改动这 100 个页面,我们要改的仅仅是这个工厂类:
//class UserFactory { public static function Create( $id,$pre = 'aaa' ) { return new User( $id ,$pre); } }
其他100个页面不用做任何改动,这就是工厂设计模式带来的好处。看下UML图:
三、观察者模式
观察者模式为您提供了避免组件之间紧密耦合的另一种方法。该模式非常简单:观察者模式是一种事件系统,意味着这一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候,观察类可以收到通知并且做出相应的动作;
现在有两派,有的人建议使用设计模式,有的人不建议使用设计模式!
这就好比写文章一样,有的人喜欢文章按照套路走,比如叙事性质的文章,时间,地点,人物,事件。而有的人喜欢写杂文或者散文,有的人喜欢写诗词!
现在写代码很多地方类似于写文章,但是在有些地方比写文章需要更多的技能!写文章写多了一般也能写出优秀的文章,而代码也一样,写多了也能写出很多有写的代码!
很多时候,我看设计模式的时候,有些设计模式只是吻合我的代码习惯。但是你硬去套它,那么反而适得其反。——很多时候是学会了招式,在应用中不知不觉的使用上这些招式,才能掌握其道,但是也不要拘泥于招式,正所谓“无招胜有招”吗?
我学设计模式的初衷,就是知道有这么个玩意儿?脑子里有这么个印象,也不会生套它!如果设计模式不符合你的习惯对你阅读代码反而是不利的!
观察者模式定义对象的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新!
设计原则
在观察者模式中,会改变的是主题的状态以及观察者的数目。用这个模式,你可以改变依赖于主题状态的对象,却不必改变主题。——找出程序中会变化的方面,然后将其和固定不变的方面相分离!
主题和观察者都使用接口:观察者利用主题的接口向主题注册,而主题利用观察者接口通知观察者。这样可以让两者之间运作正常,又同时具有松耦合的优点! ——针对接口编程,不针对实现编程!
观察者模式利用“组合”将许多观察者组合进主题中。对象(观察者——主题)之间的这种关系不是通过继承产生的,而是在运行时利用组合的方式产生的。 ——多用组合,少用继承!
好了,不说太多废话,直接上代码:
<?php /** * 观察者模式 * @author: Fantasy * @date: 2017/02/17 */ class Paper{ /* 主题 */ private $_observers = array(); public function register($sub){ /* 注册观察者 */ $this->_observers[] = $sub; } public function trigger(){ /* 外部统一访问 */ if(!empty($this->_observers)){ foreach($this->_observers as $observer) { $observer->update(); } } } } /** * 观察者要实现的接口 */interface Observerable { public function update(); } class Subscriber implements Observerable{ public function update() { echo "Callback\n"; } }?>
下面是测试代码:
/* 测试 */ $paper = new Paper(); $paper->register(new Subscriber()); //$paper->register(new Subscriber1()); //$paper->register(new Subscriber2());$paper->trigger();
总结
当新对象要填入的时候,只需要在主题(又叫可观察者)中进行注册(注册方式很多,你也可以在构造的时候,或者框架访问的接口中进行注册),然后实现代码直接在新对象的接口中进行。这降低了主题对象和观察者对象的耦合度。
好的设计模式不会直接进入你的代码中,而是进入你的大脑中。
更多PHP常用的三种设计模式 相关文章请关注PHP中文网!