博客列表 >1205_依赖注入和服务容器复习及设计模式 第29课

1205_依赖注入和服务容器复习及设计模式 第29课

叮叮当当
叮叮当当原创
2019年12月06日 23:07:51679浏览

1. 将课堂代码全部上机操作至少一遍以上

单例模式:demo1.php

  1. # 单例模式
  2. namespace _1205;
  3. use PDO;
  4. class Temp{
  5. }
  6. $obj1 = new Temp();
  7. $obj2 = new Temp();
  8. var_dump($obj1, $obj2); # id不一样
  9. echo '<br>';
  10. var_dump($obj1===$obj2);
  11. echo '<hr>';
  12. # 单例模式原理
  13. class Demo1{
  14. # 将构造方法私有化
  15. private function __construct(){
  16. }
  17. # 目前只能在类内部将类实例化
  18. # 当前类的实例
  19. public static $instance = null;
  20. # 实例化当前类的方法
  21. public static function getInstance(){
  22. # 实例化当前类,并返回类实例/对象
  23. # 判断是否已经被实例化: 若没有实例化,实例下; 若已实例化,直接返回它
  24. if( is_null(self::$instance) ){
  25. self::$instance = new self();
  26. }
  27. return self::$instance;
  28. }
  29. # 禁用克隆方法
  30. private function __clone(){
  31. }
  32. }
  33. $obj1 = Demo1::getInstance();
  34. $obj2 = Demo1::getInstance();
  35. var_dump($obj1===$obj2);
  36. echo '<br>';
  37. var_dump($obj1, $obj2); # id一样
  38. echo '<hr>';
  39. # 单例模式应用场景
  40. class Db{
  41. # 将构造方法私有化, 只能在类内部调用
  42. private function __construct(...$connectParams){
  43. $dsn = $connectParams[0];
  44. $name = $connectParams[1];
  45. $pwd = $connectParams[2];
  46. self::$pdo = new PDO($dsn, $name, $pwd);
  47. }
  48. # 目前只能在类内部将类实例化
  49. # 当前类的实例
  50. public static $pdo = null;
  51. # 实例化当前类的方法
  52. public static function getInstance(...$connectParams){
  53. # 实例化当前类,并返回类实例/对象
  54. # 判断是否已经被实例化: 若没有实例化,实例下; 若已实例化,直接返回它
  55. if( is_null(self::$pdo) ){
  56. # 构造函数不需要返回
  57. new self(...$connectParams); # 不是self::$instance = new self(...$connectParams);
  58. }
  59. return self::$pdo;
  60. }
  61. # 禁用克隆方法
  62. private function __clone(){
  63. }
  64. }
  65. $connectParams = ['mysql:host=127.0.0.1;dbname=SqlTest;charset=utf8','root','root'];
  66. $pdo = Db::getInstance(...$connectParams);
  67. $sql = 'SELECT * FROM `zsgc` WHERE `id`>1 AND `id`<4;';
  68. $data = $pdo->query($sql)->fetchAll(PDO::FETCH_ASSOC);
  69. echo '<pre>' .print_r( $data,true ). '</pre>';

工厂模式:demo2.php

  1. # 工厂模式:批量创建类的实例/对象
  2. namespace _1205;
  3. class Demo2{
  4. }
  5. # file1
  6. $obj = new Demo2();
  7. # file2
  8. $obj = new Demo2();
  9. # file3
  10. $obj = new Demo2();
  11. class Test1{
  12. public function __construct( $arg1 ){
  13. echo '对象创建成功,参数是'.$arg1;
  14. }
  15. }
  16. class Test2{
  17. public function __construct( $arg1, $arg2 ){
  18. echo '对象创建成功,参数是'.implode(', ',[$arg1, $arg2]);
  19. }
  20. }
  21. class Test3{
  22. public function __construct( $arg1, $arg2, $arg3){
  23. echo '对象创建成功,参数是'.implode(', ',[$arg1, $arg2, $arg3]);
  24. }
  25. }
  26. # 创建工厂类,专用于创建类实例
  27. class factory{
  28. public static function create($className, ...$argments ){
  29. new $className(...$argments);
  30. }
  31. }
  32. //echo Test1::class; # 完整类名,带命名空间
  33. # 用工厂类创建类实例/对象
  34. Factory::create( Test1::class, 100);
  35. echo '<br>';
  36. Factory::create( Test2::class, 100,200);
  37. echo '<br>';
  38. Factory::create( Test3::class, 100,200,300);
  39. echo '<br>';

复习(依赖注入和服务容器)

1 依赖注入( 降低对象之间耦合 ):demo3.php

  1. # 依赖注入:解决对象调用之间耦合
  2. # 目标:将类方法中的new干掉
  3. namespace _1205;
  4. # 工作类
  5. class Person{
  6. # 要依赖的外部对象
  7. private $car = null;
  8. # 注入点放到构造方法中,将依赖的外部对象全部实例化
  9. public function __construct(){
  10. $this->car = new Car();
  11. }
  12. # 外部对象执行一个动作
  13. public function work(){
  14. return $this->car->drive();
  15. }
  16. }
  17. # 依赖的外部类
  18. class Car{
  19. public function drive(){
  20. return '开车去上班';
  21. }
  22. }
  23. # 实例化类
  24. $person = new Person();
  25. echo $person->work();
  26. echo '<hr>';
  27. # 工作类
  28. class Person1{
  29. # 要依赖的外部对象
  30. private $car = null;
  31. # 注入点放到构造方法中,将依赖的外部对象全部实例化
  32. public function __construct( Car1 $car ){
  33. $this->car = $car;
  34. }
  35. # 外部对象执行一个动作
  36. public function work(){
  37. return $this->car->drive();
  38. }
  39. }
  40. # 依赖的外部类
  41. class Car1{
  42. public function drive(){
  43. return '开车去上班,呀呀呀';
  44. }
  45. }
  46. # 实例化类
  47. # 把工作类里new干掉 拎到外面注入,降低耦合
  48. $car = new Car1();
  49. $person = new Person1( $car );
  50. echo $person->work();
  51. echo '<hr>';

2.1 容器小案例之准备一:Product.php

  1. namespace _1205;
  2. class Product{
  3. public function get( Maker $maker){
  4. return '该手机由<span style="color:green;font-weight: bolder">'. $maker->get(). '</span>生产的';
  5. }
  6. }

2.2 容器小案例之准备二:Maker.php

  1. # 制造商
  2. namespace _1205;
  3. class Maker{
  4. public function get( ){
  5. return '华为';
  6. }
  7. }

2.3 容器小案例之对比( 先不用容器 ):demo1.php

  1. # 先不用容器
  2. namespace _1205;
  3. require "Product.php";
  4. require "Maker.php";
  5. class Client1{
  6. # 输出商品与制造商
  7. public function show(){
  8. # 创建产品的实例
  9. $product = new Product();
  10. # 创建制造商的实例
  11. $maker = new Maker();
  12. # 制造商注入到产品类中
  13. return $product->get( $maker );
  14. }
  15. }
  16. # 客户端调用
  17. echo ( new Client1() )->show();

2.4 容器小案例之准备三:Container.php

  1. # 容器类
  2. namespace _1205;
  3. # 引用闭包别名
  4. use \Closure;
  5. class Contatiner{
  6. # 类实例容器
  7. protected $instance = [];
  8. # 将类实例化的过程绑定到容器中
  9. public function bind( $alias, Closure $process ){
  10. $this->instance[$alias] = $process;
  11. }
  12. # 取出供养在容器中的实例化过程的闭包,并执行它
  13. public function make($alias){
  14. return $this->instance[$alias](); # 闭包,括号不能少
  15. }
  16. }

2.5 容器小案例之调用:demo2.php

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

工厂方法实例之准备一:Car.php

  1. namespace base\inc1;
  2. class Car{
  3. public function drive(){
  4. return '开汽车';
  5. }
  6. }

工厂方法实例之准备二:Plane.php

  1. namespace base\inc1;
  2. class Plane{
  3. public function drive(){
  4. return '乘飞车';
  5. }
  6. }

工厂方法实例之准备三:Train.php

  1. namespace base\inc1;
  2. class Train{
  3. public function drive(){
  4. return '坐火车';
  5. }
  6. }

工厂方法实例之准备四:autoload.php

  1. # 自动加载 是让命名空间的路径和文件所在路径一致
  2. spl_autoload_register( function ($className){
  3. # 将"\"替换成路径分隔符, 推荐使用常量:DIRECTORY_SEPARATOR, 而不是"/",可跨平台支持
  4. $path = str_replace('\\', DIRECTORY_SEPARATOR, $className);
  5. require dirname(__DIR__) . DIRECTORY_SEPARATOR . $path . '.php';
  6. });

工厂方法实例之对比( 先使用传统方法 ):Travel1.php

  1. # 旅行类: 使用最传统方式
  2. namespace base;
  3. # 设置引用外部类名的别名
  4. use base\inc1\Car;
  5. use base\inc1\Train;
  6. use base\inc1\Plane;
  7. require __DIR__ . '/autoload.php';
  8. class Travel1{
  9. # 交通工具
  10. private $vehicle;
  11. public function __construct( $vehicle ){
  12. switch( strtolower($vehicle) ){
  13. case 'car':
  14. $this->vehicle = new Car();
  15. break;
  16. case 'train':
  17. $this->vehicle = new Train();
  18. break;
  19. case 'plane':
  20. $this->vehicle = new Plane();
  21. }
  22. }
  23. # 调用外部一个依赖对象
  24. public function travelModel(){
  25. return $this->vehicle->drive() . ' : 去旅行';
  26. }
  27. }
  28. # 客户端调用
  29. echo (new Travel1('car'))->travelModel(), '<br>';
  30. echo (new Travel1('train'))->travelModel(), '<br>';
  31. echo (new Travel1('plane'))->travelModel(), '<br>';

工厂方法实例之调用:Travel2.php

  1. # 旅行类: 使用工厂类(此时工作类依赖工厂类,而工厂类依赖3个外部类)
  2. namespace base;
  3. # 设置引用外部类名的别名
  4. use base\inc1\Car;
  5. use base\inc1\Train;
  6. use base\inc1\Plane;
  7. require __DIR__ . '/autoload.php';
  8. # 工厂类, 专用于创建类实例
  9. class Factory
  10. {
  11. protected static $instance = null;
  12. public static function getInstance( $vehicle )
  13. {
  14. switch( strtolower($vehicle) ){
  15. case 'car':
  16. self::$instance = new Car();
  17. break;
  18. case 'train':
  19. self::$instance = new Train();
  20. break;
  21. case 'plane':
  22. self::$instance = new Plane();
  23. }
  24. # 返回当前具体的交通工具
  25. return self::$instance;
  26. }
  27. }
  28. class Travel2{
  29. # 交通工具
  30. private $vehicle;
  31. public function __construct( $vehicle ){
  32. $this->vehicle = Factory::getInstance( $vehicle );
  33. }
  34. # 调用外部一个依赖对象
  35. public function travelModel(){
  36. return $this->vehicle->drive() . ' : 去流浪';
  37. }
  38. }
  39. # 客户端调用
  40. echo (new Travel2('car'))->travelModel(), '<br>';
  41. echo (new Travel2('train'))->travelModel(), '<br>';
  42. echo (new Travel2('plane'))->travelModel(), '<br>';

接口实例之准备一:iVehicle.php

  1. namespace base\inc2;
  2. # 交通工具的接口
  3. interface iVehicle{
  4. public function drive();
  5. }

接口实例之准备二:接口子类 Car.php ( Plane.php / Train.php同理 )

  1. namespace base\inc2;
  2. class Car implements iVehicle {
  3. public function drive(){
  4. return '开汽车';
  5. }
  6. }

接口实例之调用:Travel3.php

  1. # 旅行类: 使用一个接口 (此时工作类仅依赖一个接口类)
  2. # 3个外部类继承接口并实现接口方法,工作类注入的3个外部类实例此时都是接口实例,做到面向接口
  3. # 好处:可以更方便的扩展代码,如新增ship类,只需继承接口并实现接口方法,工作类再注入此接口实例
  4. namespace base;
  5. # 设置引用外部类名的别名
  6. use base\inc2\Car;
  7. use base\inc2\Train;
  8. use base\inc2\Plane;
  9. use base\inc2\iVehicle;
  10. require __DIR__ . '/autoload.php';
  11. class Travel3{
  12. # 交通工具
  13. private $vehicle;
  14. # 注入接口实例
  15. public function __construct( iVehicle $vehicle ){
  16. $this->vehicle = $vehicle;
  17. }
  18. # 调用外部一个依赖对象
  19. public function travelModel(){
  20. return $this->vehicle->drive() . ' : 去闯荡';
  21. }
  22. }
  23. # 客户端调用
  24. echo (new Travel3( new Car() ))->travelModel(), '<br>';
  25. echo (new Travel3( new Train() ))->travelModel(), '<br>';
  26. echo (new Travel3( new Plane() ))->travelModel(), '<br>';

2. 手写课堂笔记:1205.md

总结:

  • 1. 单例模式:创建类的唯一实例
  • 2. 工厂模式:批量创建类实例
  • 3. 依赖注入:在外部实例化,并将实例注入到类中,避免直接在类里实例化,降低耦合
  • 4. 服务容器:将类的实例化过程与容器绑定,并通过容器类来执行,统一管理,而不是在外部各自随便实例化
  • 5. 面向接口编程:先通过传统方法实现,缺点是工作类与外部类耦合性太高;然后通过工厂方法实例改进,虽降低了工作类与外部类的耦合,但工厂类依旧依赖外部类;最后通过面向接口的方法,使外部类实例都成了接口实例,达到了工作类只依赖接口类的效果,统一了实例化过程,后续扩展代码更加方便
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议