减少手动对象实例化
我想学习依赖倒置原则。目前我的代码是这样的减少手动对象实例化
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,而不是与我最初的代码块结束了?这是一件好事吗?
当我读到你的问题时,我觉得你有两个主要目标。首先要提高代码的可读性('..让程序员的生活'),其次是从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);
使用抽象工厂类来处理处理I/O所需的对象的实例化。您可以将工厂注入示例类,或让工厂实例化所需的对象,然后将这些对象注入示例类。然后,你可以这样做:
$IOFactory = new IOFactory();
$example = new Example($IOFactory::makeInputHandler($inputType), $IOFactory::makeOutputHandler($outputType));
$example->doStuffToOutput();
IOFactory负责在其特定类型的实例输入和输出对象基地,然后实例化处理程序,并与输入和输出对象注入其中。之后返回要在示例对象中注入的处理程序对象。
在你的情况,你可以选择许多可用的造物设计模式之一。我的建议是使用工厂模式或对象池模式。 在工厂方法模式的情况下,你可以有一个类创建对象的责任:
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中也变得方便。
看来,在你的第一个例子中,无法定义处理程序类型(ConsoleInputHandler/ConsoleOutputHandler/FileInputHandler/FileOutputHandler)。这是你试图解决的问题吗? – TechWisdom