2015-07-19 64 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中也变得方便。