2015-07-19 3 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

Пока я читал ваш вопрос, я чувствовал, что у вас есть две основные цели. Во-первых, чтобы улучшить читабельность вашего кода («... запустите жизнь программиста») и, во-вторых, отделить класс «Пример» от обработчиков ввода-вывода. По моему мнению, DI - это просто принцип, который следует соблюдать, чтобы достичь ваших целей.

Прежде чем я прикреплю какой-либо код, я хочу подчеркнуть, что иногда лучше всего сочетать ваш код. Код должен быть каким-то образом связан. Не используйте DI везде только потому, что это было сказано. Простота, как описано с принципами KISS и YAGNI, всегда является победителем.

Итак, большой вопрос в том, является ли ваша вторая цель (развязка с помощью DI) разумной вещью. Есть ли реальная причина для изменения InputHandler/OutputHandler в классе «Exmaple»? Если «Нет» - ваш ответ, я бы рекомендовал вам сохранить его внутри этого класса. И «возможно, в далеком будущем это будет выгодно» на самом деле не рассчитывается.

Однако, если ваши обработчики должны быть уникальными для каждого типа (файла, консоли и т. Д.), И ваша развязка поможет вам и другим программистам расширить платформу, вы можете воспользоваться шаблоном 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

Использование абстрактного класса Factory для обработки экземпляров объектов, необходимых для обработки ввода-вывода. Вы можете либо ввести фабрику в класс примера, либо позволить фабрике создавать экземпляры необходимых объектов, а затем вводить их в класс примера. Тогда вы можете сделать:

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

IOFactory заботится о инстанцировании ввода и вывод объекты базы в их конкретных типах, а затем инициализирует обработчик и вводить их с входным и выходным объектом. Затем возвращает объекты обработчика, которые должны быть введены в объект примера.

0

В вашем случае вы можете выбрать один из многих порождающих паттернов проектирования, доступных. Мое предложение - пойти либо с шаблоном Factory pattern, либо с шаблоном пула объектов. В случае фабричного метода шаблона, вы можете иметь класс с ответственностью создания объекта:

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. вы можете изменить синтаксис и использовать соответственно. Это не единственный способ реализовать Factory Pattern.

Если вы хотите снять бремя создания объекта во время выполнения, вы можете использовать шаблон пула объектов. Гибрид шаблона прототипа также становится удобным в вашем csse.

Смежные вопросы