理解依赖注入 for Zend framework 2

前端之家收集整理的这篇文章主要介绍了理解依赖注入 for Zend framework 2前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

依赖注入(Dependency Injection),也称为控制反转(Inversion of Control),一种设计模式,其目的是解除类之间的依赖关系。

假设我们需要举办一个Party,Party需要主持人、厨师、灯光、音响、食品、酒水等等。那么Party对他们存在依赖关系。用程序语言表示如下:

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  1. //Party.PHP
  2. class Party{
  3. //主持人
  4. private $_host;
  5.  
  6. function __construct(){
  7. include "./Host.PHP";
  8. $this->_host = new Host();
  9. }
  10.  
  11. function startParty(){
  12. $this->_host->sayHello();
  13. }
  14. }
  15.  
  16. //Host.PHP
  17. class Host{
  18. private $_name;
  19. function sayHello(){
  20. echo "My name is " . $this->_name;
  21. }
  22. }
  23.  
  24. //main
  25. $party = new Party();
  26. $party->startParty();

可见Party的运行依赖于Host,没有Host,Party不能单独运行,也不能单独发布为组件。为了解除Party对Host的依赖,我们可以这么做:

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  1. //Party.PHP
  2. class Party{
  3. //主持人
  4. private $_host;
  5.  
  6. function __construct($host = ""){
  7. if($host){
  8. $this->_host = $host;
  9. }
  10. }
  11.  
  12. function startParty(){
  13. $this->_host->sayHello();
  14. }
  15.  
  16. function setHost($host){
  17. $this->_host = $host;
  18. }
  19. }
  20.  
  21. //Host.PHP
  22. class Host{
  23. private $_name;
  24. function sayHello(){
  25. echo "My name is " . $this->_name;
  26. }
  27. }
  28.  
  29. //main
  30. $host = new Host();
  31. $party = new Party();
  32. $party->setHost($host);//或者 $party = new Party($host)
  33. $party->startParty();

此时Party类对Host类的依赖被移到外面,运行时Host类通过构造函数或者setter注入到Party中。Party本身可以被单独发布。如果Host没有sayHello方法,将其注入到Party中必然导致异常。为了约束Host必须含有sayHello方法,可以使用接口。

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  1. //Party.PHP
  2. class Party{
  3. //主持人
  4. private $_hostInterface;
  5.  
  6. function __construct($host = ""){
  7. if($host){
  8. $this->_hostInterface = $host;
  9. }
  10. }
  11.  
  12. function startParty(){
  13. $this->_hostInterface->sayHello();
  14. }
  15.  
  16. function setHost($host){
  17. $this->_hostInterface = $host;
  18. }
  19. }
  20.  
  21. //HostInterface.PHP
  22. Interface HostInterface{
  23. public function sayHello();
  24. }
  25.  
  26. //Host.PHP
  27. class Host implement HostInterface{
  28. private $_name;
  29. function sayHello(){
  30. echo "My name is " . $this->_name;
  31. }
  32. }
  33.  
  34. //main
  35. $host = new Host();
  36. $party = new Party();
  37. $party->setHost($host);//或者 $party = new Party($host)
  38. $party->startParty();

这么做实际上已经达到了解耦的目的,那么下面我要把Party所有依赖的厨师、灯光、音响、食品、酒水都加进去,会是怎样?

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  1. //Party.PHP
  2. class Party{
  3. //主持人
  4. private $_host;
  5. private $_cooker;
  6. private $_wine;
  7. private $_food;
  8. private $_music;
  9. private $_light;
  10.  
  11. function __construct(){
  12. }
  13.  
  14. function startParty(){
  15. $this->_host->sayHello();
  16. }
  17.  
  18. function setHost($host){
  19. $this->_host = $host;
  20. }
  21.  
  22. function setCooker($cooker){
  23. $this->_cooker = $cooker;
  24. }
  25.  
  26. function set Wine($wine){
  27. $this->_wine = $wine;
  28. }
  29.  
  30. //...等等 food,light,music
  31. }
  32.  
  33. ]
  34. //Host.PHP
  35. class Host{
  36. private $_name;
  37. function sayHello(){
  38. echo "My name is " . $this->_name;
  39. }
  40. }
  41. //Cooker.PHP
  42. class Cooker{}
  43. class Wine{}
  44. clsas Light{}
  45. //...等等其他类
  46.  
  47. //main
  48. $host = new Host();
  49. $cooker = new Cooker();
  50. $wine = new Wine();
  51. //...等等
  52. $party = new Party();
  53. $party->setHost($host);
  54. $party->setCooker($cooker);
  55. $party->setWine($wine);
  56. $party->setFood($food);
  57. $part->setMusic($music);
  58. $part->setLight($light);
  59. $party->startParty();

代码中大量的实例化和setter调用,是否可以优化?我们需要一个DI容器,在DI中管理各个类,由DI负责注入。此时的DI更像是一个“大工厂模式”。

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  1. //Party.PHP
  2. class Party{
  3. private $_di;
  4.  
  5. function __construct(){
  6. }
  7.  
  8. function startParty(){
  9. $this->_di->get("Host")->sayHello();
  10. $this->_di->get("Cooker")->cook();
  11. //...
  12. }
  13.  
  14. function setDI($di){
  15. $this->_di = $di;
  16. }
  17. }
  18.  
  19. //HostInterface.PHP
  20. Interface HostInterface{
  21. public function sayHello();
  22. }
  23.  
  24. //Host.PHP
  25. class Host implement HostInterface{
  26. private $_name;
  27. function sayHello(){
  28. echo "My name is " . $this->_name;
  29. }
  30. }
  31.  
  32. //main
  33. $di = new DI();
  34. //匿名函数形式
  35. $di->set("Host", function(){
  36. return new Host();
  37. });
  38. //类名
  39. $di->set("Cooker", "Path\To\Cooker.PHP");
  40. //直接返回实例
  41. $di->set("Wine", new Path\To\Wine.PHP);
  42. //数组
  43. $di->set("Light", array("className" => "Path\To\Light"));
  44.  
  45. $party = new Party();
  46. $party->setDI($di);
  47. $party->startParty();

DI使用set来注册服务类,注册的方式可以有很多种,他们都是惰性实例化,set时并不实例化,在get时才会实例化。而DI在注册服务类时通常会使用配置来实现,如JSON、XML或者PHP数组。

DI非常注重约定,$di->get(“Host”)获取的实例如果不是Host实例的话,将会引发异常。因此,DI属于强约定模式,通常用于底层架构,Zend framework 2的核心部分使用DI模式,但在框架应用层使用服务定位模式(ServiceLocator),服务定位模式与依赖注入非常相似,都能够解除类之间的依赖关系,且实现思路与DI基本一致。

参考资料:
理解PHP 依赖注入
话说 依赖注入(DI) or 控制反转(IoC)
用PHP实现简单的控制反转(IOC) 依赖注入(DI),用JSON配置文件
——————————————–
本站除标注[FW]和资讯文章外都为原创文章,转载请注:
转载来源: Coming X
原文链接: 理解依赖注入 for Zend framework 2

猜你在找的设计模式相关文章