Re: [请益] Dependency Injection 疑问

楼主: banjmin (HD)   2015-06-09 22:08:50
你要设计一个方法,要能通过floppy bird的关卡
一种鸟只能飞低、超低、高、超高
假设你写了一个这样只能飞高的鸟的class
class FlyHighBird
{
public function fly()
{
return "fly high";
}
}
但是floppy bird的关卡的class中
Class Stage
{
private $bird;
private $interspace;
function __construct()
{
$this->bird = new FlyHighBird();
}
function check()
{
if($this->bird->fly() == $interspace)
return true;
return false;
}
// other method dynamically change $interspace
}
Stage在编译时期就决定依赖于Bird物件
那么你这只只能飞高的鸟,势必过不了关卡现在空隙位置是
低、超低、或超高的检查
那么要能一直通过不同高度的关卡检查,
你势必要在runtime改变Stage依赖的物件才行
其实Stage根本不care你是哪种鸟,甚至根本不care你是不是鸟,
他只在乎你是飞的高还是飞的低,也就是只在乎你的
"飞的行为",你手边有四种鸟都只能飞不同的高度,那么你只要能动态改变Stage依赖
的$bird物件中的实作,似乎就能通过每一次的检查
所以你把"飞的行为"从四种鸟的class中一般化成接口
interface FlyBehavior
{
public function fly();
}
四种鸟分别实作这个接口完成四种不同高度的飞行行为
改变Stage相依的物件
class Stage
{
private $flyBehavior;
private $interspace;
function setFlyBehavior($flyBehavior)
{
$this->flyBehavior = $flyBehavior;
}
function check()
{
if($this->flyBehavior->fly() == $interspace)
return true;
return false;
}
//other methods
}
现在Stage 没有在编译时期依赖于某一种鸟类了,而是透过FlyBehavior接口
从Stage的外部注入其中一种鸟类的实作,来动态透过setFlyBehavior的替换目前
依赖的实作,这种依赖关系从原本自己物件内部,到被抽到外部决定再透过setter
或建构子注入就是依赖注入,能做到runtime才根据一些参数
(比如说Stage有个方法getInterspace()提供给你$interspace的数值,再在外部加以判断)
决定要注入哪一种实作,来达到通过每一次检查的弹性
将来floppy bird改版了,要检查是否到达"宇宙的高度",才算通过
你只要打造一个火箭的Class,一样完成FlyBehavior的实作,让他飞到宇宙的高度
再注入到Stage物件就能通过关卡了,而你"并没有修改Stage一开始相依物件的程式码"
因为Stage原本直接依赖于某种鸟类的实作,这样的关系被"接口"decoupling了
也就是"针对接口写程式,不要针对实作写程式"的OO守则
配合DI的方式能做到更多面对需求变更时,还能保有弹性,你要修改的程式少了很多
作者: tkdmaf (皮皮快跑)   2015-06-10 00:56:00
甚至不care你是不是鸟XDD...
作者: Den3 (Den)   2015-06-10 08:46:00
想请问这是为了解决不要重新编译的问题,那PHP这种直译的情况下也适用吗?没事,不好意思,刚刚短路,搞错重点
作者: y2468101216 (芸)   2015-06-10 09:23:00
推好文应该要M
作者: chan15 (ChaN)   2015-06-10 13:15:00
谢谢大大的热情回应,原理跟使用方式我懂,我想问的是情境以一般继承的 class 来讲,功能可能多半集中在自己有些共同 function 去 parent 拿,这是一般的配置DI 的设计是把功能在 Stage 操作,注入不同 class换 class 等于换 config,而且是有 function 的 config怎样的情境才有使用的绝对差异呢,举例一个问题DI http://pastebin.com/1NFCEW0yabstract http://pastebin.com/nz6u8ceL这两个结果一样,abstract 甚至可以继承 parent 东西来用所以我想问这个原则跟使用情境
楼主: banjmin (HD)   2015-06-10 22:50:00
重点还是要看需求多复杂,你的例子太小了,其实没什么差差别可能就是假设你今天面对新需求势必要继承另一个class语言没有多重继承的时候 原本继承的做法就做不下去了你势必要换成接口的做法abstract class用的好的例子 可以看看template pattern满足开放封闭原则,看看decorator pattern怎么使用DI不过不管pattern怎么样,重点还是你想做什么功能再来谈适合的、有弹性的设计,pattern例子通常不能直接套

Links booklink

Contact Us: admin [ a t ] ucptt.com