减少手动对象实例化

时间:2015-07-19 22:14:37

标签: php oop solid-principles

我正在努力学习依赖倒置原则。目前我的代码是这样的

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实现此目的,而不是最终使用我的初始代码块?这是一件好事吗?

3 个答案:

答案 0 :(得分:2)

使用Abstract Factory类来处理处理i / o所需的对象的实例化。您可以将工厂注入示例类,或让工厂实例化所需的对象,然后将它们注入示例类。然后你可以这样做:

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

IOFactory负责以其特定类型实例化输入和输出对象,然后实例化处理程序并使用输入和输出对象注入它们。然后返回要在示例对象中注入的处理程序对象。

答案 1 :(得分:2)

在我阅读你的问题时,我觉得你有两个主要目标。首先是为了提高代码的可读性(让程序员的生活更轻松),其次是解耦"示例"来自I / O处理程序的类。就我而言,DI只是为了实现目标而遵循的原则。

在我附加任何代码之前,我想强调一下,有时候实际结合代码会更好。代码必须以某种方式耦合。不要因为已经说过而到处使用DI。正如KISS和YAGNI原则所描述的那样,简单性始终是赢家。

因此,最重要的问题是你的第二个目标(与DI脱钩)是否是明智之举。是否存在" Exmaple"中的InputHandler / OutputHandler的真正原因?上课要改变?如果"否"是你的答案,我建议你把它保持在这个类中。并且"也许在遥远的未来它将是有利可图的"并不算数。

但是,如果您的处理程序对于每种类型(文件,控制台等)都应该是唯一的,并且您的解耦将帮助您和其他程序员扩展平台,您可以利用Factory模式。您有几种方法可以实现此模式(静态/抽象/简单/方法工厂)。主要目标是减少客户的学习曲线,并制作"示例" class解耦,因此添加更多类型或处理程序不会影响此类。

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 :(得分: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中给出了示例。您可以更改语法并相应地使用。这不是实现工厂模式的唯一方法。

如果要在运行时消除创建对象的负担,可以使用对象池模式。原型模式的混合也在你的csse中变得很方便。