2016-03-05 166 views
3

假設:(1)有一類具有一個構造,其方法使用噴射物體,如:爲什麼我們需要一個構造函數?

class SomeClass 
{ 
    protected $object1; 
    protected $object2; 

    public function __construct(
     Object1Interface $object1, 
     Object2Interface $object2 
    ) { 
     $this->object1 = $object1; 
     $this->object2 = $object2; 
    } 

// methods that use Object1 and Object2 classes by $this->object1 and $this->object2. 
} 

和(2)有此相同的類,沒有構造函數,但類方法接受Object1Object2作爲依賴,像這樣:

class SomeClass 
{ 
    public function doStuff1(Object1Interface $object1) 
    {// do the stuff} 

    public function doStuff2(Object2Interface $object2) 
    {// do the stuff} 
} 

在互聯網上有很多例子提倡第一個變體。

但這些有什麼區別?

+0

在第一個,一旦你構造,就不再需要之前正確地設置不斷將這些對象傳遞給方法。在第二種情況下,你必須不斷地傳入對象。如果每次傳入'doStuff'時對象不同,但是如果我們正在討論依賴注入*,那麼首選項是首選。 –

+0

區別在於你必須在調用第二個方法之前在你的主代碼中的某處實例化對象。那不一定是壞的,只是不同而已 – RiggsFolly

回答

3

他們是不同的,並沒有真正提倡一個在另一個。

(1)被廣泛稱爲構造函數依賴注入。它被認爲是更好的,首選的形式,而不是(2)。這些依賴關係對消費者是「隱藏的」,通常在對象生命週期中不會改變。

考慮抽象的HTTP客戶端:

$httpClient = new HttpClient(new CurlAdapter()); 
// or 
$httpClient = new HttpClient(new SocketAdapter()); 

開關電源適配器,不影響客戶是如何使用的:因爲它強制執行依賴注入

$response = $httpClient->get($url); 

構造DI提倡優越於setter方法。此外,setter通常允許在對象生命週期中改變依賴關係,改變它的行爲並打開可能的棘手難以調試的錯誤。 (2)在不同的使用情況下使用,通常不與DI重疊。(2)在不同的使用情況下使用,通常不與DI重疊。 以這種方式傳遞依賴關係有各種原因。它們可能是交互界面的一部分,在對象生命週期中經常變化或在通話時間決定。依賴關係在概念上可能不屬於對象,但仍然需要該特定操作。重要的是他們不應該存儲在對象中,並以可能導致副作用的方式使用!

class SomeClass 
{ 
    protected $dep; 

    public function doSomething(DepInterface $dep) 
    { 
     // do the stuff 
     // store dep for later 
     $this->dep = $dep; 
     // This is similar to issue with setters but much worse. 
     // Side effect is not obvious 
    } 

    public function doSomethingElse() 
    { 
     $this->dep->increment(); 
    } 
} 

for ($i = 0; $i < 100; $i++) { 
    $foo->doSomething($bar); 
    if (rand(0, 100) == $i) { 
     // represents conditions out of direct control. 
     // such as conditional or timing errors, alternative flows, 
     // unanticipated code changes 
     $foo->doSomethng($baz); 
    } 
    $foo->doSomethingElse(); 
} 
// what will be the result? 

考慮這個DDD比如解決一些不切實際的問題:

class Bus 
{ 
    public function board(Passenger $passenger, TicketingService $tservice) 
    { 
     // @todo check bus have seats 
     // throws exception if ticket is invalid 
     $tservice->punchPassengerTicket($this, $passenger); 
     $this->passengers[] = $passenger; 
    } 
} 

if ($bus->isIntercity()) { 
    $ticketingService = new BookingService(); 
} else { 
    $ticketingService = new PrepaidCityTransportCardsService(); 
} 
$bus->board($passenger, $ticketingService); 

在這個例子中,我們明確地強制寄宿總線需要門票和車票都在登機打孔。但是,如果我們要在Bus實例化中注入TicketingService,即使對於根本沒有登機的情況,我們也會得到更復雜的依賴關係圖。通過服務執行操作,但從不存儲它會降低複雜性,並在此情況下顯着提高可測試性。

該技術在域驅動設計環境中被稱爲雙派遣(不要與Double Dispatch混淆)並廣泛使用。
您可能認爲我們可以在登機前檢查車票,並完全取消對票務服務的依賴。那麼,這是另一個話題。

1

第一大benifit是,你總是在那裏。如果你有含2變量x和y的一個點類的對象是「正確的」

的狀態

第一種方式確保x和y總是存在於類中(不爲null),所以方法可以使用它們。

第二裝置每個方法將必須檢查是否x和y是使用它們

兩者都有優點和缺點雖然

相關問題