Blogger Information
Blog 29
fans 0
comment 0
visits 19739
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
服务容器与设计模式的学习(单例模式 和 工厂模式的应用)-PHP培训十期线上班
手机用户1576673622
Original
758 people have browsed it

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

一、单例模式的原理

  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个类; 抽象工厂模式,运用接口的方式来实现,与普通工厂相比,代码量更少,灵活性更高,出错概率低 ,维护更方便。

Correcting teacher:天蓬老师天蓬老师

Correction status:qualified

Teacher's comments:设计模式有很多, 咱们课堂时间有限, 无法一一举例, 更多的还需要同学私下努力
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post