2015-07-19 87 views
1

我想學習依賴倒置原則。目前我的代碼是這樣的減少手動對象實例化

class Example { 
    public function __construct($input, $output) { 
     $input_handler = new InputHandler($input); 
     $output_handler = new OutputHandler($output); 

     $input_handler->doStuff(); 
     $output_handler->doOtherStuff(); 
    } 
} 

$input = new Input(); 
$output = new Output(); 
$example = new Example($input, $output) 

但是,它似乎使用基本的依賴注入,它應該更像這樣嗎?

class Example { 
    public function __construct($input_handler, $output_handler) { 
     $input_handler->doStuff(); 
     $output_handler->doOtherStuff(); 
    } 
} 

$input   = new Input(); 
$output   = new Output(); 
$input_handler = new InputHandler($input); 
$output_handler = new OutputHandler($output); 
$example  = new Example($input_handler, $output_handler) 

這是正確的嗎?

我想讓程序員在運行程序時選擇輸入/輸出的類型。因此,依賴注入(據我所知)它看起來像這樣;

$input   = new ConsoleInput(); 
$output   = new FileOutput(); 
$input_handler = new ConsoleInputHandler($input); 
$output_handler = new FileOutputHandler($output); 
$example  = new Example($input_handler, $output_handler); 
$example->doStuffToOutput(); 

不過,我寧願只需要在輸入和輸出的類型,請通過讓程序員生活更容易,而無需擔心處理它們的類;

$input = new ConsoleInput(); 
$output = new FileOutput(); 
$example = new Example($input, $output); 
$example->doStuffToOutput(); 

甚至

$example = new Example(new ConsoleInput(), new FileOutput()); 
$example->doStuffToOutput(); 

我怎樣才能做到這一點使用DIP,而不是與我最初的代碼塊結束了?這是一件好事嗎?

+0

看來,在你的第一個例子中,無法定義處理程序類型(ConsoleInputHandler/ConsoleOutputHandler/FileInputHandler/FileOutputHandler)。這是你試圖解決的問題嗎? – TechWisdom

回答

2

當我讀到你的問題時,我覺得你有兩個主要目標。首先要提高代碼的可讀性('..讓程序員的生活'),其次是從I/O處理程序中分離出「Example」類。就我而言,DI是達到目標的理想原則。

在附上任何代碼之前,我想強調一下,有時最好是實際耦合代碼。代碼必須以某種方式耦合。只是因爲有人說過,不要在任何地方使用DI。正如KISS和YAGNI原則所描述的那樣,簡單一直是贏家。

所以這裏最大的問題是你的第二個目標(與DI解耦)是否明智。 「Exmaple」類中的InputHandler/OutputHandler是否有真正的原因需要更改?如果「否」是你的答案,我會建議你保持這個類完好無損。而且「也許在遙遠的將來它會有利可圖」並不算真正的數字。但是,如果您的處理程序應該對每種類型(文件,控制檯等)都是唯一的,並且您的解耦將幫助您和其他程序員擴展平臺,則可以利用Factory模式。你有幾種實現這種模式的方法(靜態/抽象/簡單/方法工廠)。主要目標是減少客戶端的學習曲線,並使「示例」類解耦,以便添加更多類型或處理程序不會影響此類。

class HandlerFactory { 

    protected static function createInputHandler(Input $input) 
    { 
     switch ($input) 
     { 
      case is_a($input, 'FileInput'): 
       return new FileInputHandler($input); 
      case is_a($input, 'ConsoleInput'): 
       return new ConsoleInputHandler($input); 
     } 

     throw new \Exception('Missing Input handler'); 
    } 

    protected static function createOutputHandler(Output $output) 
    { 
     switch ($output) 
     { 
      case is_a($output, 'FileOutput'): 
       return new FileOutputHandler($output); 
      case is_a($output, 'ConsoleOutput'): 
       return new ConsoleOutputHandler($output); 
     } 

     throw new \Exception('Missing Output handler'); 
    } 

    public static function createHandler($io) 
    { 
     switch ($io) 
     { 
      case is_a($io, 'Input'): 
       return self::createInputHandler($io); 
      case is_a($io, 'Output'): 
       return self::createOutputHandler($io); 
     } 

     throw new \Exception('Missing I/O handler'); 
    } 
} 

現在在你的問題你的第一個代碼仍然是相關的與未成年人扭曲:

class Example { 
    public function __construct($input, $output) { 
     $input_handler = HandlerFactory::createHandler($input); 
     $output_handler = HandlerFactory::createHandler($output); 

     $input_handler->doStuff(); 
     $output_handler->doOtherStuff(); 
    } 
} 

$input = new Input(); 
$output = new Output(); 
$example = new Example($input, $output); 
2

使用抽象工廠類來處理處理I/O所需的對象的實例化。您可以將工廠注入示例類,或讓工廠實例化所需的對象,然後將這些對象注入示例類。然後,你可以這樣做:

$IOFactory = new IOFactory(); 
$example = new Example($IOFactory::makeInputHandler($inputType), $IOFactory::makeOutputHandler($outputType)); 
$example->doStuffToOutput(); 

IOFactory負責在其特定類型的實例輸入和輸出對象基地,然後實例化處理程序,並與輸入和輸出對象注入其中。之後返回要在示例對象中注入的處理程序對象。

0

在你的情況,你可以選擇許多可用的造物設計模式之一。我的建議是使用工廠模式或對象池模式。 在工廠方法模式的情況下,你可以有一個類創建對象的責任:

class ObjectFactory { 
    public InputHandler createInputHandlerObject(inputobj){ 
     if(inputobj instanceOf ConsoleInput) { 
     return new ConsoleInputHandler(); 
     } else if(inputobj instanceOf FileInput) { 
     } 
    } 
// similarly create a method for creating OutputHandler object. 
//create the appropriate object by using instanceOf operator. 

由於我熟悉Java我已經在Java中給出的例子。您可以更改語法並相應地使用。這不是實施工廠模式的唯一方法。

如果您想消除運行時創建對象的負擔,您可以使用對象池模式。原型圖案的混合在您的CSS中也變得方便。