博客列表 >12月5日-单例模式、工厂模式及依赖管理-***线上九期班

12月5日-单例模式、工厂模式及依赖管理-***线上九期班

邯郸易住宋至刚
邯郸易住宋至刚原创
2019年12月19日 00:29:03684浏览

一、课堂代码全部上机操作至少一遍以上

1、单例模式 demo1.php

代码

  1. <?php
  2. namespace _1205;
  3. //use PDO;
  4. // 单例模式
  5. class Temp
  6. {
  7. //只是一个类,不需要成员,为了演示 ...
  8. }
  9. //获取第一个对象
  10. $obj1 = new Temp();
  11. //获取第二个对象
  12. $obj2 = new Temp();
  13. //查看两个都是从一个类实例化对象的类型
  14. var_dump($obj1, $obj2);
  15. echo '<br>';
  16. //查看两个对象是否完全一样
  17. var_dump($obj1 === $obj2);
  18. echo '<hr>';
  19. // 单例模式原理
  20. class Demo1
  21. {
  22. // 构造方法私有化,禁止外部访问
  23. //外部实例化该类时,首先调用构造函数
  24. private function __construct()
  25. {
  26. }
  27. // 目前 由于构造函数已经私有化,外部调用是非法的,所以只能在类中的内部将类实例化
  28. // 当前类的实例 静态属性
  29. public static $instance = null;
  30. // 实例化当前类的方法 静态方法
  31. public static function getInstance()
  32. {
  33. // 实例化当前类,并返回类实例/对象
  34. // 判断当前类是否已经被实例化过了,如果没有的话就实例化,如果已实例化,就返回它
  35. //is_null()这个函数用来判断变量值是否为null,如果是null,返回true否则false
  36. if (is_null(self::$instance)) {
  37. //在当前类中调用类属性,使用self,同时self也是类本身
  38. //对类进行实例化new self(),然后返回类实例对象,保存在变量$instance当中
  39. self::$instance = new self();
  40. }
  41. //如果已经实例化,返回类实例对象本身
  42. return self::$instance;
  43. }
  44. // 禁用克隆魔术方法
  45. private function __clone()
  46. {
  47. // ...
  48. }
  49. }
  50. //new Demo1();
  51. $obj1 = Demo1::getInstance();
  52. $obj2 = Demo1::getInstance();
  53. //查看两个实例对象是否完全相同
  54. var_dump($obj1 === $obj2);
  55. echo '<br>';
  56. //查看两个对象的类型
  57. var_dump($obj1, $obj2);
  58. echo '<hr>';

结果

2、单例模式应用场景

代码

  1. <?php
  2. // 单例模型应用场景
  3. class Db
  4. {
  5. // 构造方法私有化 禁止外部调用
  6. //...$connectParams是可变参数...$connectParams===$dsn,$username,$password
  7. private function __construct(...$connectParams)
  8. {
  9. //初始化变量
  10. $dsn = $connectParams[0];
  11. $username = $connectParams[1];
  12. $password = $connectParams[2];
  13. //连接数据库
  14. self::$pdo = new \PDO($dsn, $username, $password);
  15. }
  16. // 目前 由于构造方法的私有化,所以只能在类中的内部将类实例化
  17. // 当前类的实例 静态属性
  18. public static $pdo = null;
  19. // 实例化当前类的方法
  20. public static function getInstance(...$connectParams)
  21. {
  22. // 实例化当前类,并返回类实例/对象
  23. // 判断当前类是否已经被实例化过了,如果没有的话就实例化,如果已实例化,就返回它
  24. if (is_null(self::$pdo)) {
  25. // 构造函数不需要返回,这里需要特别注意
  26. new self(...$connectParams);
  27. }
  28. //返回数据库连接
  29. return self::$pdo;
  30. }
  31. // 禁用克隆魔术方法
  32. private function __clone()
  33. {
  34. // ...
  35. }
  36. }
  37. echo '<hr>';
  38. //客户端调用
  39. //配置数据库连接参数$dsn,$username,$password
  40. $connectParams = ['mysql:host=localhost;dbname=mt', 'root', '111'];
  41. //实例化同时,传入数据库连接参数,连接数据库
  42. $pdo = Db::getInstance(...$connectParams);
  43. //这里直接调用了query()方法,是为了简便演示进程,没有使用预处理过程,一般数据是从数据库中获取
  44. //在这里直接打印输出
  45. //PDO中的query和fetchAll方法
  46. echo '<pre>' .print_r($pdo->query('SELECT * FROM `user`')->fetchAll(),true) .'</pre>';

结果

3、工厂模式 demo2.php

代码

  1. <?php
  2. namespace _1205;
  3. // 工厂模式: 用于批量创建类的实例/对象
  4. use mvc\Facade;
  5. class Demo2
  6. {
  7. // ...
  8. }
  9. //如果需要很多类的对象,那就需要做大量重复的操作,
  10. // file1.php
  11. $obj = new Demo2();
  12. // file2.php
  13. $obj = new Demo2();
  14. // file3.php
  15. $obj = new Demo2();
  16. /********************************************/
  17. class Test1
  18. {
  19. //构造函数,外部调用该类时,首先调用构造函数
  20. public function __construct($arg1)
  21. {
  22. echo '对象创建成功, 参数是: ' . $arg1;
  23. }
  24. }
  25. class Test2
  26. {
  27. public function __construct($arg1, $arg2)
  28. {
  29. echo '对象创建成功, 参数是: ' . implode(', ', [$arg1, $arg2]);
  30. }
  31. }
  32. class Test3
  33. {
  34. public function __construct($arg1, $arg2, $arg3)
  35. {
  36. //implode(',',[$arg1,$arg2,$arg3])= '$arg1,$arg2,$arg3';
  37. echo '对象创建成功, 参数是: ' . implode(', ', [$arg1, $arg2, $arg3]);
  38. }
  39. }
  40. // 工厂类, 专用于创建类实例
  41. class Factory
  42. {
  43. //静态方法 $className 类名 ...$arguments是可变变量
  44. public static function create($className, ...$arguments)
  45. {
  46. //根据传过来的类名和参数,对类进行实例化,并返回实例对象
  47. return new $className(...$arguments);
  48. }
  49. }
  50. //echo Test1::class; // _1205\Test1: 完整的类名, 带有命名空间的
  51. //Test1::class是完整的类名,是带有命名空间的类名,在本命名空间下是指 _1205\Test1
  52. // 用工厂类来创建类实例/对象
  53. Factory::create(Test1::class, 100);
  54. echo '<br>';
  55. Factory::create(Test2::class, 100, 200);
  56. echo '<br>';
  57. Factory::create(Test3::class, 100, 200, 300);

结果

4、_1205\base\Travel1.php

代码

  1. <?php
  2. // ***类: 使用最传统的方式
  3. namespace base;
  4. // 设置引用的外部类名的别名
  5. use base\inc1\Car;
  6. use base\inc1\Train;
  7. use base\inc1\Plane;
  8. require __DIR__ . '/autoload.php';
  9. class Travel1
  10. {
  11. // 交通工具 私有属性 只能在类内部调用,子类也不能调用
  12. private $vehicle;
  13. // 构造方法
  14. public function __construct($vehicle)
  15. {
  16. //根据外部传入参数来对私有属性$vehicle存入相应类实例化得到的对象
  17. switch (strtolower($vehicle)) {
  18. case 'car':
  19. $this->vehicle = new Car();
  20. break;
  21. case 'train':
  22. $this->vehicle = new Train();
  23. break;
  24. case 'plane':
  25. $this->vehicle = new Plane();
  26. }
  27. }
  28. // 调用外部一个依赖对象
  29. public function travelModel()
  30. {
  31. //此时的$this->vehicle就是某个类的实例化对象,所以会调用相应类中的方法
  32. return $this->vehicle->drive() . ' : 去***';
  33. }
  34. }
  35. // 客户端调用
  36. echo (new Travel1('car'))->travelModel(), '<br>';
  37. echo (new Travel1('train'))->travelModel(), '<br>';
  38. echo (new Travel1('plane'))->travelModel(), '<br>';

结果

5、_1205\base\Travel2.php

代码

  1. <?php
  2. // ***类: 使用最传统的方式
  3. namespace base;
  4. // 设置引用的外部类名的别名
  5. use base\inc1\Car;
  6. use base\inc1\Train;
  7. use base\inc1\Plane;
  8. use base\inc1\Ship;
  9. require __DIR__ . '/autoload.php';
  10. // 工厂类, 专用于创建类实例
  11. class Factory
  12. {
  13. //添加静态变量static $instance 用于存储类实例
  14. protected static $instance = null;
  15. //外部传入参数,得到相应类的实例对象
  16. public static function getInstance($vehicle)
  17. {
  18. switch (strtolower($vehicle)) {
  19. case 'car':
  20. //类内调用该类属性使用self::
  21. self::$instance = new Car();
  22. break;
  23. case 'train':
  24. self::$instance = new Train();
  25. break;
  26. case 'ship':
  27. self::$instance = new Ship();
  28. break;
  29. case 'plane':
  30. self::$instance = new Plane();
  31. }
  32. // 返回当前具体的交通工具
  33. return self::$instance;
  34. }
  35. }
  36. class Travel2
  37. {
  38. // 交通工具
  39. private $vehicle;
  40. // 构造方法
  41. public function __construct($vehicle)
  42. {
  43. //Factory::getInstance($vehicle)==self::$instance
  44. //此时的$this->vehicle就是Factory::getInstance($vehicle)==self::$instance
  45. //就是一个类实例
  46. $this->vehicle = Factory::getInstance($vehicle);
  47. }
  48. // 调用外部一个依赖对象
  49. public function travelModel()
  50. {
  51. //$this->vehicle是类实例,可以调用相应的类中的方法
  52. return $this->vehicle->drive() . ' : @@@@ 去***';
  53. }
  54. }
  55. // 客户端调用
  56. echo (new Travel2('car'))->travelModel(), '<br>';
  57. echo (new Travel2('train'))->travelModel(), '<br>';
  58. echo (new Travel2('plane'))->travelModel(), '<br>';
  59. echo (new Travel2('ship'))->travelModel(), '<br>';

结果

6、_1205\base\Travel3.php

代码

  1. <?php
  2. // 旅行类: 使用最传统的方式
  3. namespace base;
  4. // 设置引用的外部类名的别名
  5. use base\inc2\Car;
  6. use base\inc2\Train;
  7. use base\inc2\Plane;
  8. use base\inc2\Ship;
  9. use base\inc2\iVehicle;
  10. require __DIR__ . '/autoload.php';
  11. class Travel3
  12. {
  13. // 交通工具 私有属性,只能在本类内部调用,外部、子类都不能调用
  14. private $vehicle;
  15. // 构造方法
  16. public function __construct(iVehicle $vehicle)
  17. {
  18. //属性$this->vehicle初始化
  19. $this->vehicle = $vehicle;
  20. }
  21. // 调用外部一个依赖对象
  22. public function travelModel()
  23. {
  24. return $this->vehicle->drive() . ' : ======= 去旅行';
  25. }
  26. }
  27. // 客户端调用
  28. $car = new Car();
  29. echo (new Travel3($car))->travelModel(), '<br>';
  30. //new Train()作为参数传给new Travel3(),然后调用travelModel()
  31. echo (new Travel3(new Train()))->travelModel(), '<br>';
  32. echo (new Travel3(new Plane()))->travelModel(), '<br>';
  33. echo (new Travel3(new Ship()))->travelModel(), '<br>';

结果

7、容器 _1205\lesson1\demo1.php

代码

  1. <?php
  2. namespace _1205;
  3. require 'Product.php';
  4. require 'Maker.php';
  5. // 先不用容器,将外部类的对象的依赖直接放在本类中实例化
  6. class Client1
  7. {
  8. // 输出商品与制造商
  9. public function show()
  10. {
  11. // 创建产品的实例
  12. $product = new Product();
  13. // 创建制造商的实例
  14. $maker = new Maker();
  15. // 制造商注入到产品类中
  16. return $product->get($maker);
  17. }
  18. }
  19. // 客户端调用
  20. echo (new Client1())->show();

结果

8、容器 _1205\lesson1\demo2.php

代码

  1. <?php
  2. namespace _1205;
  3. require 'Product.php';
  4. require 'Maker.php';
  5. require 'Container.php';
  6. //使用容器类
  7. class Client2
  8. {
  9. // 输出商品与制造商
  10. public function show(Product $product, Maker $maker)
  11. {
  12. // 制造商注入到产品类中
  13. return $product->get($maker);
  14. }
  15. }
  16. // 客户端调用
  17. // 将类实例绑定到容器中并实例化且返回
  18. $container = new Container();
  19. // 将实例化代码绑定到容器中
  20. $container->bind('product', function () {return new Product();});
  21. $container->bind('maker', function () {return new Maker();});
  22. // 创建类实例并返回
  23. $product = $container->make('product');
  24. $maker = $container->make('maker');
  25. echo (new Client2())->show($product, $maker);

结果

二、手写1205.md

三、总结

1、容器Container

容器中存入了所依赖的类的实例对象队列,并且将类与类实例化代码的闭包函数绑定到容器中,bind()方法是放进去,make()是调用容器中的实例化方法。

2、依赖注入

类分为工作类和依赖类
工作类中需要调用其它类时,为了降低耦合度,需要将对被依赖的类的实例过程中的new消灭掉,这就是依赖注入的目的。

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