减少手动对象实例化
Reducing manual object instantiation
我正在努力学习依赖倒置原则。目前我的代码是这样的
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 实现这一点而不以我的初始代码块结束?这是一件好事吗?
使用抽象工厂class 来处理i/o 所需对象的实例化。您可以将工厂注入示例 class,或者让工厂实例化所需的对象,然后将它们注入示例 class。然后你可以这样做:
$IOFactory = new IOFactory();
$example = new Example($IOFactory::makeInputHandler($inputType), $IOFactory::makeOutputHandler($outputType));
$example->doStuffToOutput();
IOFactory 负责根据特定类型实例化输入和输出对象,然后实例化处理程序并将它们注入输入和输出对象。之后 returns 将处理程序对象注入到示例对象中。
在阅读您的问题时,我觉得您有两个主要目标。首先是提高代码的可读性(“..简化程序员的生活”),其次是将 "Example" class 与 I/O 处理程序分离。在我看来,DI 只是为了达到你的目标而遵循的原则。
在附加任何代码之前,我想强调的是,有时实际耦合代码会更好。代码必须以某种方式耦合。不要仅仅因为有人说过就到处使用 DI。正如 KISS 和 YAGNI 原则所描述的那样,简单永远是赢家。
所以这里的大问题是您的第二个目标(与 DI 解耦)是否是明智之举。 "Exmaple" class 中的 InputHandler / OutputHandler 是否有更改的真正原因?如果 "No" 是您的答案,我建议您将其原封不动地保存在 class 中。 "maybe in the distant future it will be profitable" 并不算数。
但是,如果您的处理程序对于每种类型(文件、控制台等)应该是唯一的,并且您的解耦将帮助您和其他程序员扩展平台,您可以利用工厂模式。您有多种方法来实现此模式(静态/抽象/简单/方法工厂)。主要目标是减少客户端的学习曲线,并使 "Example" class 解耦,以便添加更多类型或处理程序不会影响此 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);
在您的情况下,您可以从众多可用的创意设计模式中选择一种。我的建议是使用工厂模式或对象池模式。
在工厂方法模式的情况下,你可以有一个 class 负责创建对象:
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 中也变得很方便。
我正在努力学习依赖倒置原则。目前我的代码是这样的
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 实现这一点而不以我的初始代码块结束?这是一件好事吗?
使用抽象工厂class 来处理i/o 所需对象的实例化。您可以将工厂注入示例 class,或者让工厂实例化所需的对象,然后将它们注入示例 class。然后你可以这样做:
$IOFactory = new IOFactory();
$example = new Example($IOFactory::makeInputHandler($inputType), $IOFactory::makeOutputHandler($outputType));
$example->doStuffToOutput();
IOFactory 负责根据特定类型实例化输入和输出对象,然后实例化处理程序并将它们注入输入和输出对象。之后 returns 将处理程序对象注入到示例对象中。
在阅读您的问题时,我觉得您有两个主要目标。首先是提高代码的可读性(“..简化程序员的生活”),其次是将 "Example" class 与 I/O 处理程序分离。在我看来,DI 只是为了达到你的目标而遵循的原则。
在附加任何代码之前,我想强调的是,有时实际耦合代码会更好。代码必须以某种方式耦合。不要仅仅因为有人说过就到处使用 DI。正如 KISS 和 YAGNI 原则所描述的那样,简单永远是赢家。
所以这里的大问题是您的第二个目标(与 DI 解耦)是否是明智之举。 "Exmaple" class 中的 InputHandler / OutputHandler 是否有更改的真正原因?如果 "No" 是您的答案,我建议您将其原封不动地保存在 class 中。 "maybe in the distant future it will be profitable" 并不算数。
但是,如果您的处理程序对于每种类型(文件、控制台等)应该是唯一的,并且您的解耦将帮助您和其他程序员扩展平台,您可以利用工厂模式。您有多种方法来实现此模式(静态/抽象/简单/方法工厂)。主要目标是减少客户端的学习曲线,并使 "Example" class 解耦,以便添加更多类型或处理程序不会影响此 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);
在您的情况下,您可以从众多可用的创意设计模式中选择一种。我的建议是使用工厂模式或对象池模式。 在工厂方法模式的情况下,你可以有一个 class 负责创建对象:
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 中也变得很方便。