博客列表 >服务容器与设计模式的学习(单例模式 和 工厂模式的应用)-PHP培训十期线上班

服务容器与设计模式的学习(单例模式 和 工厂模式的应用)-PHP培训十期线上班

手机用户1576673622
手机用户1576673622原创
2020年02月22日 22:38:47759浏览

在数据库访问时,数据库对外提供的连接数是有限的,因此一个用户只需创建一个链接就可以,采用“单例模式”设计,判断某个类是否已经创建过实例,可实现这个目的。下面演示“单例模式”的原理

一、单例模式的原理

  1. <?php
  2. //文件: src\inc\Singleten.php;
  3. //没有传入参数的情况
  4. namespace src\inc;
  5. class Singleten{
  6. private static $selfObj;
  7. //禁用构造方法
  8. private function __construct()
  9. {
  10. //...
  11. }
  12. //禁用clone
  13. private function __clone()
  14. {
  15. //...
  16. }
  17. //判断是否已创建过类实例
  18. public static function getInstance()
  19. {
  20. if (is_null(static::$selfObj)) {
  21. static::$selfObj=new self();
  22. }
  23. return static::$selfObj;
  24. }
  25. }
  26. $pdo=Singleten::getInstance();
  27. $pdo1=Singleten::getInstance();
  28. var_dump($pdo===$pdo1);
结果

在编程过程中,某个.php文件常常要通过(new)关键字引用多个类的实例,当某个类被多个.php文件调用,而突然不得不改名时,意味着所有调用了该类的文件全部都得重新更正调用的类名称。采用工厂模式编程,可解决这个问题。下面演示工厂模式的两种模式:普通工厂 抽象工厂

二、工厂模式的实现(以购物分类:线上支付线下支付为例)

1. 普通工厂

线上支付类
  1. <?php
  2. //文件:src\inc1\Online.php;
  3. namespace src\inc1;
  4. class Online
  5. {
  6. public function purchase(){
  7. echo '线上转帐';
  8. }
  9. }
线下支付类
  1. <?php
  2. //文件:src\inc1\Offline.php;
  3. namespace src\inc1;
  4. class Offline
  5. {
  6. public function purchase(){
  7. echo '线下现金支付';
  8. }
  9. }
普通工厂类
  1. <?php
  2. //文件:src\inc1\Factory.php;
  3. namespace src\inc1;
  4. class Factory
  5. {
  6. private static $shopWays;
  7. public static function getInstance(string $shopWays)
  8. {
  9. switch (strtolower($shopWays)):
  10. case 'online':
  11. static::$shopWays = new Online();
  12. break;
  13. case 'offline':
  14. static::$shopWays = new Offline();
  15. break;
  16. endswitch;
  17. return static::$shopWays;
  18. }
  19. }
普通工厂调用
  1. <?php
  2. //文件:src\inc1\Shopping.php;
  3. namespace src\inc1;
  4. class Shopping
  5. {
  6. public static function purchase($shopWays){
  7. Factory::getInstance($shopWays)->purchase();
  8. }
  9. }
自动加载类(略)
客户端调用
  1. <?php
  2. //文件:src\inc1\Main.php;
  3. namespace src\inc1;
  4. require '..\autoload.php';
  5. $shopWays=Shopping::purchase('online');
  6. echo '<br>';
  7. $shopWays=Shopping::purchase('offline');
结果

===================================================================

2. 抽象工厂

线上支付类
  1. <?php
  2. //文件:src\inc2\Online.php;
  3. namespace src\inc2;
  4. class Online implements IShopping
  5. {
  6. public function purchase(){
  7. echo '线上转帐';
  8. }
  9. }
线下支付类
  1. <?php
  2. //文件:src\inc2\Offline.php;
  3. namespace src\inc2;
  4. class Offline implements IShopping
  5. {
  6. public function purchase(){
  7. echo '线下现金支付';
  8. }
  9. }
抽象工厂(接口)
  1. <?php
  2. //文件: src\inc2\IShopping.php
  3. namespace src\inc2;
  4. interface IShopping
  5. {
  6. public function purchase();
  7. }
抽象工厂调用
  1. <?php
  2. //文件: src\inc2\Shopping.php
  3. namespace src\inc2;
  4. class Shopping
  5. {
  6. public static function purchase(IShopping $ishopping){
  7. $ishopping->purchase();
  8. }
  9. }
自动加载类(略)
客户端调用
  1. <?php
  2. //文件: src\inc2\Main.php
  3. namespace src\inc2;
  4. require '..\autoload.php';
  5. $shopWays=Shopping::purchase(new Online());
  6. echo '<br>';
  7. $shopWays=Shopping::purchase(new Offline());
结果

===================================================================

下面以数据库访问为例结合单例模式演示抽象工厂的原理:分别以PDO和Mysqli方式进行数据库查询select()操作。

三、抽象工厂的原理(接口实现)

数据库接口(抽象工厂)
  1. <?php
  2. //文件: src\inc\IDataBase.php;
  3. namespace src\inc;
  4. interface IDataBase
  5. {
  6. public function select(): array;
  7. }
Mysqli类
  1. <?php
  2. //文件: src\inc\Mysqli.php;
  3. namespace src\inc;
  4. class Mysqli implements IDataBase {
  5. private static $mysqli=null;
  6. private static $selfObj=null;
  7. private function __construct(...$arguments)
  8. {
  9. static::$mysqli = new \Mysqli(...$arguments);
  10. }
  11. //类实例
  12. public static function getInstance(...$argument)
  13. {
  14. if (is_null(static::$selfObj)) {
  15. static::$selfObj=new self(...$argument);
  16. }
  17. return static::$selfObj;
  18. }
  19. //禁用clone
  20. private function __clone()
  21. {
  22. //...
  23. }
  24. //设置变量
  25. public function __set(string $name, $value)
  26. {
  27. $this->{$name}=$value;
  28. }
  29. //查询
  30. public function select(): array
  31. {
  32. return static::$mysqli->query($this->sql)->fetch_All(MYSQLI_ASSOC);
  33. }
  34. }
PDO类
  1. <?php
  2. //文件: src\inc\PDO.php;
  3. namespace src\inc;
  4. class PDO implements IDataBase{
  5. private static $pdo=null;
  6. private static $selfObj=null;
  7. private function __construct(...$arguments)
  8. {
  9. static::$pdo = new \PDO(...$arguments);
  10. }
  11. //类实例
  12. public static function getInstance(...$argument)
  13. {
  14. if (is_null(static::$selfObj)) {
  15. static::$selfObj=new self(...$argument);
  16. }
  17. return static::$selfObj;
  18. }
  19. //禁用clone
  20. private function __clone()
  21. {
  22. //...
  23. }
  24. public function __set(string $name, $value)
  25. {
  26. $this->{$name}=$value;
  27. }
  28. public function select(): array
  29. {
  30. return static::$pdo->query($this->sql)->fetchAll(\PDO::FETCH_ASSOC);
  31. }
  32. }
接口调用
  1. <?php
  2. //文件: src\inc\DataBase.php;
  3. namespace src\inc;
  4. class DataBase
  5. {
  6. public static function select(IDataBase $idatabase): array
  7. {
  8. return $idatabase->select();
  9. }
  10. }

自动加载类

  1. <?php
  2. //文件 src\autoload.php;
  3. spl_autoload_register(function ($clasName) {
  4. $file = str_replace('\\', DIRECTORY_SEPARATOR, (dirname(__DIR__) . '\\' . $clasName)) . '.php';
  5. file_exists($file) ? require $file : '加载失败,文件不存在';
  6. });

客户端调用

  1. <?php
  2. //文件: src\inc\Main.php;
  3. namespace src\inc;
  4. require '..\autoload.php';
  5. //Mysqli查询`phpedu`.`staffs`表中第1条记录
  6. $mysqli = Mysqli::getInstance('db.io', 'root', 'root', 'phpedu');
  7. $mysqli->sql='SELECT * FROM `staffs`;';
  8. echo "数据库(`phpedu`).表(`staffs`)首条记录:";
  9. echo '<pre>' . print_r(DataBase::select($mysqli)[0],true) . '</pre>';
  10. //PDO查询`phpedu`.`users`表中第1条记录
  11. $pdo = PDO::getInstance('mysql:host=db.io;dbname=phpedu', 'root', 'root');
  12. $pdo->sql='SELECT * FROM `users`;';
  13. echo "数据库(`phpedu`).表(`users`)首条记录:";
  14. echo '<pre>' . print_r(DataBase::select($pdo)[0],true) . '</pre>';
结果(数据库表格略)

总结

单例模式,通过将构造方法(construct())、克隆方法(clone())从外部禁用,而从内部控制实例化的方式,有效避免类的重复实例化.
工厂模式是将原构造方法中实例化依赖对象的过程,交给工厂类完成。其中,普通工厂模式,通过判断条件,根据输入不同的类别实例化不同的类,将原来的依赖多个类变成依赖1个类; 抽象工厂模式,运用接口的方式来实现,与普通工厂相比,代码量更少,灵活性更高,出错概率低 ,维护更方便。

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议