php中常见的几种设计模式

xiaoxiao2021-02-28  99

1. 单例模式

单例模式可以说是面向对象语言里最常用、也是最简单的一种模式。单例就是单个实例,单个对象的意思,就是说我们去实例化一个类的时候,不管调用多少次,都永远只有一个实例, 不会有多个,这样就节省了内存分配开支。

先简单说下单例模式的原理:将构造函数__construct设置为私有的private, 对外提供一个static静态方法比如:getInstance获得实例,在getInstance方法里来做统一判断是否有new一个实例,有的话直接返回,没有就new一个,这样就保证了不管外面调用多少次,只保证new了一次。

直接上代码,举例来说明下:

<?php /** * 1.单例模式 Single.php */namespace Lib; class Single { static private $instance; /** * 在单例模式下,要将构造方法设为私有的,这样在外部就不能实例化 */ private function __construct() { } /** * 这个是获取实例化对象的入口,是静态方法,不需要new,可以直接调用 */ static public function getInstance() { //判断一下$instance是否已经存在 if (!isset(self::$instance)) { self::$instance = new Single(); } return self::$instance; } public function get() { echo 'you get it!'; }}

在index.php中,我们来实例化调用一下。

define('WWWDIR', __DIR__); include WWWDIR . '/Lib/Load.php'; spl_autoload_register('\\Lib\\Load::autoload'); // 1. 单例模式$single = Lib\Single::getInstance(); $single2 = Lib\Single::getInstance(); $single->get(); //you get it! $single2->get(); //you get it! var_dump($single === $single2); //boolean true

从打印结果我们看出,$single1和$single2其实是同一个引用的,这样就达到了我们的目的。而且也节约了内存。在同一个生命周期中,不管调用多次,永远只有一个实例。

2. 工厂模式

先简单说下工厂模式:当我要实例化类的时候,不直接new这个类,而是通过调用另一个类的一个方法来实例化。这就是工厂模式的核心原理。

这样的好处有啥呢?

假设不使用工厂模式:比如很多地方调用类class_a,代码就会这样子创建一个实例:new class_a(), 假设某天需要把class_a类的名子修改成class_b,意味着很多调用的代码都要修改。如果你用工厂模式,就你只需要改一处就可以了。当然这只是一个很极端的例子,没人会吃饱了没事干会去修改类名。这也是工厂模式最简单的用法。工厂模式最多的用法,就是根据条件来创建不同的实例,比如你传入一个mysql,我去实例化mysql类给你,你传入sql server,那我就实例化sql server类给你。有点像switch干的活。这样就简化了逻辑,统一控制,代码也比较简化。

还是直接上代码来说明:

<?php/** * 2.Factory.php 工厂模式 * User: tonyyang * Date: 4/2 0002 * Time: 15:19 */ namespace Lib; class Factory { static public function create() { /** * 在同样一个命名空间下,要这样直接调用。这样调用是会报错:Lib\FactoryTest1(); * 它去找Lib\Lib\FactoryTest1.php 这个文件去了。 */ // return new FactoryTest1(); return new FactoryTest2(); } } <?php/** * Created by PhpStorm. * User: tonyyang * Date: 4/2 0002 * Time: 15:22 */ namespace Lib; class FactoryTest2 { public function __construct() { } public function get() { echo 'factory get it!'; }} //2.工厂模式 //不用工厂模式,我在很多地方调用一个类是这样的。new Lib\FactoryTest1();new Lib\FactoryTest1();new Lib\FactoryTest1();new Lib\FactoryTest1(); //用工厂模式,我不直接去new FactoryTest1这个类,我是通过Factory这个类的create方法来$test1 = Lib\Factory::create();$test1->get(); //假如我现在吃饱了犯傻,将FactoryTest1的类名改成FactoryTest2了,普通的写法是这样:new Lib\FactoryTest2();new Lib\FactoryTest2();new Lib\FactoryTest2();new Lib\FactoryTest2(); //用了工厂模式,还是一模一样的写法,我通过修改Factory类里的create方法这一处就可以了。$test1 = Lib\Factory::create();$test1->get();

工厂模式的第二张方式就是统一管理,通过传参的方式来实例化,最常见的DB,也可能有Mysql,也有可能有SqlServer:

static public function db($dbName){ if (empty($dbName)) { return new Db\Mysql(); } //选择判断 switch ($dbName) { case 'mysql': return new Db\Mysql(); break; case 'sql_server': return new Db\SqlServer(); break; }}

这样,我就可以通过参数传递的方式,来选择数据库连接了。

//通过传参数的方式来实现切换不同的数据库实例$mysql = Lib\Factory::db('mysql');$sqlServer = Lib\Factory::db('sql_server');

3. 注册模式

注册模式在单例模式的基础上进一步拓展了一步,他把所有单例模式的对象全部保存在一个索引数组中,下次取得时候,直接去数组里按照索引去取。这样的好处是在程序中有条理的存放并管理对象。所以,肯定有一个存(set)和一个取(get)。一般是先去取如果没有,就重新初始化然后存起来,这样这个周期中的其他代码就可以直接取了。和redis缓存的道理是一样的。

我先来实现注册模式的代码:

<?php/** * 3. 注册模式 * * @package Register.php */namespace Lib; class Register{ protected static $_config; /** * 获取变量值 * * @param string $name * @return string */ public static function get($name) { if (self::isRegister($name)) { return self::$_config[$name]; } else { return false; } } /** * 设置变量值 * * @param string $name * @param string $value * @return string */ public static function set($name, $value) { if (!isset($name) || !isset($value)) { return false; } self::$_config[$name] = $value; return self::$_config[$name]; } /** * 判断变量是否注册 * * @param string $name * @return bool */ public static function isRegister($name) { return isset(self::$_config[$name]); }}

上面代码我们定义了get和set方法。这样在一个存取模式就定义好了。

在我们的项目当中,像数据库连接,redis连接,配置文件等,都是在各个地方被大量使用的,我们完全可以使用注册模式,将这些变量对象写到注册器上面去。

下面我们来调用一下:

// 3. 注册模式 $register = Lib\Register::getInstance(); //数据库链接提前写到注册树上$register->set('mysql', new Lib\Db\Mysql());$register->set('sql_server', new Lib\Db\SqlServer()); //读取db类$register->get('mysql')->select('select * from user');$register->get('sql_server')->select('select * from user'); //redis类写到注册树上$register->set('redis', new Lib\Cache\Redis()); //读取redis类$register->get('redis')->get('redis-cache-2012'); //配置文件写到注册树上 $config = array( 'db_name' => '127.0.0.1',); $register->set('config', $config); echo $register->get('config')['db_name']; // php > 5.4

这样既实现了单例模式,又使得所有的变量类都统一管理,实现起来更简洁,而且代码效率更高,更省内存。

4. 适配器模式

就是将一些截然不同的函数接口封装成统一的API,最简单的例子就是DB类了。我们有mysql,mysqli,pdo等。如果我们项目中同时有这几种数据库存在,那么做一些操作是很蛋疼的,因为它们的都有各自额api.所以,这个时候,我们可以用适配器模式将3种不同的数据库封装成统一的api, 对外就是统一的方式调用。再比如我们项目中可能会用到的缓存有redis,memcache等,我们也同样可以把他们封装成统一的API接口。

我们用db类为例子来说明下。

//4 . 适配器模式 $register = Lib\Register::getInstance();$config = array( 'host' => '127.0.0.1', 'db_name' =>'test', 'user_name' => 'root', 'password' => '',);//用注册模式将db配置文件注册。$register->set('db', $config);//$register->set('mysql', new Lib\Db\MySQL());$register->set('mysqli', new Lib\Db\MySQLi());$register->set('pdo', new Lib\Db\PDO());//api接口一模一样$mysqlInfo = $register->get('mysql')->select('select 1+1;');$mysqliInfo = $register->get('mysqli')->select('select 1+1;');$pdoInfo = $register->get('pdo')->select('select 1+1;');var_dump($mysqlInfo, $mysqliInfo, $pdoInfo);//工厂模式来做也一样$mysql = Lib\Factory::db('mysql');$mysqli = Lib\Factory::db('mysqli');$pdo = Lib\Factory::db('pdo');//api接口一模一样$mysqlInfo = $mysql->select('select 1+1;');$mysqliInfo = $mysqli->select('select 1+1;');$pdoInfo = $pdo->select('select 1+1;');var_dump($mysqlInfo, $mysqliInfo, $pdoInfo);

5. 策略模式

6. 数据对象映射模式

7. 观察者模式

8. 原型模式

9. 装饰器模式

10. 迭代器模式

11. 代理模式

转载请注明原文地址: https://www.6miu.com/read-31383.html

最新回复(0)