Как преобразовать этот код, таким образом, он теперь использует шаблон Внедрения зависимости?

Хорошо, Таким образом, у меня есть следующая ситуация. У меня первоначально был некоторый код как это:

public class MainBoard {
    private BoardType1 bt1;
    private BoardType2 bt2;
    private BoardType3 bt3;
    ...
    private readonly Size boardSize;

    public MainBoard(Size boardSize) {
        this.boardSize = boardSize;

        bt1 = new BoardType1(boardSize);
        bt2 = new BoardType2(boardSize);
        bt3 = new BoardType3(boardSize);
    }
}

Теперь, я решил осуществить рефакторинг тот код, таким образом, зависимости классов введены, вместо этого:

public class MainBoard {
    private IBoardType1 bt1;
    private IBoardType2 bt2;
    private IBoardType3 bt3;
    ...
    private Size boardSize;

    public MainBoard(Size boardSize, IBoardType1 bt1, IBoardType2 bt2, IBoardType3 bt3) {
        this.bt1 = bt1;
        this.bt2 = bt2;
        this.bt3 = bt3;
    }
}

Мой вопрос состоит в том, что сделать о Размере Совета? Я имею в виду, в первом случае, я просто передал класс размер требуемой платы, и он сделает все для создания других видов плат с корректным размером. В случае внедрения зависимости, который не мог бы больше иметь место. Что делает Вас, парни делают в этой ситуации? Вы ставите какой-либо вид проверки MainBoardконструктор так, чтобы удостовериться, что корректные размеры передаются в? Вы просто предполагаете, что клиент класса будет достаточно ответственен для передачи 3 видов плат с тем же размером, таким образом, не будет никакой проблемы?

Править

Почему я делаю это? Поскольку мне нужен к Модульному тесту MainBoard. Я должен смочь установить эти 3 подплаты в определенных состояниях, таким образом, я могу протестировать тот свой MainBoard, делает то, к чему я ожидаю это.

Спасибо

7
задан devoured elysium 5 August 2010 в 13:07
поделиться

8 ответов

Я бы сказал, что параметр boardSize не нужен во втором случае, но я бы добавил утверждение, чтобы гарантировать, что 3 размера платы действительно равны.

Но в целом второй случай мне кажется сомнительным. Я бы предложил первый подход, если вам действительно не нужно вставлять разные типы плат в основную плату. Даже в этом случае я бы подумал об использовании, например, фабрика платы вместо передачи 3 параметров платы конструктору, например

public interface IBoardBuilderFactory {
    public IBoardType1 createBoardType1(Size boardSize);
    public IBoardType2 createBoardType2(Size boardSize);
    public IBoardType3 createBoardType3(Size boardSize);
}

Это обеспечит единообразие трех досок как в отношении «семейства досок», так и в отношении размера.

Нам следует больше узнать о модели контекста / предметной области, в частности, о взаимоотношениях основной и дочерней плат, чтобы решить, является ли здесь DI правильным выбором.

5
ответ дан 6 December 2019 в 21:08
поделиться

Сомнительно, следует ли вообще применять в этом случае внедрение зависимостей (или инверсию зависимостей). Мне кажется, что ваша MainBoard отвечает за управление жизненным циклом BoardTypes , созданных в первом примере. Если вы сейчас вводите свои BoardTypes, эту ответственность должны выполнять потребители из MainBoard .

Это компромисс между гибкостью и дополнительными пошлинами со стороны потребителя.

С другой стороны, если есть смысл, чтобы жизненный цикл BoardType обрабатывался извне , то можно использовать инверсию зависимостей. Затем ваш конструктор на MainBoard должен убедиться, что его зависимости правильно определены . Это будет включать проверку равенства их размера .

3
ответ дан 6 December 2019 в 21:08
поделиться

Основным преимуществом внедрения зависимостей является изоляция от изменений вводимых объектов. Итак, в вашем случае одна очевидная переменная - это размер.Вы бы вставили платы в основную плату, чтобы основной плате больше не нужно было знать или беспокоиться о размере. Кроме того, если вашему приложению не требуется поддерживать 3 различных поведения между различными типами плат, я бы предложил использовать одно абстрактное определение для интерфейса типа платы.

public class MainBoard {
    private IBoardType bt1;
    private IBoardType bt2;
    private IBoardType bt3;

    public MainBoard(IBoardType bt1, IBoardType bt2, IBoardType bt3) {
        this.bt1 = bt1;
        this.bt2 = bt2;
        this.bt3 = bt3;
    }
}

Ответственность за то, что выполняет внедрение (инфраструктура внедрения или код сборки), ложится на обеспечение правильного размера этих плат. Это можно сделать разными способами, например, основная плата, а все встроенные платы получают свой размер из одного внешнего источника. Возможно, в этом случае ваше приложение определяет размеры внедряемых плат относительно основной платы.

Таким образом, у вас может быть внешняя логика, такая как:

public class BoardAssembler {
   public static MainBoard assembleBoard(Size size) {
      Size innerBoardSize = deriveSizeOfInternalBoards(size);
      return new MainBoard(new BoardType1(innerBoardSize), new BoardType2(innerBoardSize), new BoardType3(innerBoardSize));
   }
}

По сути, то, что вам нужно, - это инверсия логики построения везде, где создается MainBoard. Начните с этого и извлеките все в фабрику или какую-нибудь злую синглтон-фабрику или статический метод. Спросите себя: «Где создается MainBoard?» Также спросите, «какие компоненты и параметры необходимы?» После того, как вы переместили всю логику создания экземпляра в фабрику, может упростить обслуживание Mainboard и всех ее зависимостей.

2
ответ дан 6 December 2019 в 21:08
поделиться

-EDIT- Удалил большую часть моего ответа, потому что другие опередили меня :)

Другой вариант - фабрики. В зависимости от ваших требований вам может быть лучше (или нет) использовать фабрики для решения вашей проблемы. Есть хорошее обсуждение SO здесь о Factories Vs DI. Вы могли бы даже подумать о передаче factroy через DI в конструктор вашего класса - так что ваш конструктор принимает размер и фабричный класс и подчиняется фабричному классу (передавая размер), чтобы получить платы.

1
ответ дан 6 December 2019 в 21:08
поделиться

У вас может быть BoardTypeFactory, который создает BoardTypes следующим образом:

IBoardType bt1 = BoardTypeFactory.Create (boardSize);

Обратите внимание, что существует множество сообщений в блогах и SO-ответов о том, как лучше всего написать фабрику, приведенный выше простой пример.

Затем вы можете вызвать

new MainBoard (boardSize, bt1, ....

, передав исходный размер, который использовался для создания плат.

0
ответ дан 6 December 2019 в 21:08
поделиться

Какую информацию содержит класс BoardTypeX ? Имеет ли смысл вставлять этот объект в вашу MainBoard. Внедрение зависимостей и шаблонов в целом не всегда решение, и вы не должны использовать его просто так, как вы можете. Что-то вроде заводского паттерна здесь может сработать лучше

public class MainBoard {
    private IBoardType1 bt1;
    private IBoardType2 bt2;
    private IBoardType3 bt3;
    ...
    private Size boardSize;

    public MainBoard(IBoardBuilderFactory factory) {
        this.bt1 = factory.buildBoard(boardSize);
        //...
    }
}

И если размер платы должен определяться извне, возможно, вы его вообще не храните. Возможно, фабрика определяет, какой размер платы использовать, когда она собирается в другом месте.

В любом случае, суть в том, что шаблоны проектирования нужны, чтобы помочь вам выполнять задачи чистым и поддерживаемым способом. Это не жесткие правила, которым необходимо следовать

1
ответ дан 6 December 2019 в 21:08
поделиться

Вы можете получить размер доски от одной из плат, которые проходят через DI. Таким образом можно полностью потерять переменную boardSize.

0
ответ дан 6 December 2019 в 21:08
поделиться

В рамках MainBoard , boardSize фактически является константой. Вы хотите, чтобы существовало только одно его значение. Вам понадобится такой код:

int boardSize = 24;  // Or maybe you get this from reading a file or command line
MainBoardScope mainBoardScope = new mainBoardScope( boardSize );

Если вы наивно сделали 24 глобальной или константой, у вас были бы трудно увидеть зависимости здесь, потому что классы будут полагаться на получение этой константы или глобального статически, а не через объявленный интерфейс ( т.е. конструктор).

mainBoardScope содержит «синглтоны» для группы объектов с одинаковым временем жизни. В отличие от синглтонов старой школы, они не являются глобальными и не доступны статически.Затем рассмотрите этот код, который запускается при запуске вашего приложения (или этой области в более крупном приложении) для построения графа объектов:

   MainBoardFactory factory = new MainBoardFactory( mainBoardScope );
   MainBoard board = factory.createMainBoard();

В этом методе createMainBoard вы должны использовать boardSize из области видимости для создания трех дополнительных плат:

   IBoardType1 b1 = injectBoardType1( myScope );
   IBoardType2 b2 = injectBoardType2( myScope );
   IBoardType3 b3 = injectBoardType3( myScope );
   return new MainBoard( scope.getBoardSize, b1, b2, b3 );

Требуется ли MainBoard для проверки правильности размера каждой из трех переданных в конструктор плат? Если это ваш код, создающий доски, создайте модульный тест для injectMainBoard () . Задача MainBoard - обеспечить ее правильную конструкцию. Это задача фабрики - создать ее, это юнит-тест фабрики, чтобы убедиться, что все сделано правильно.

0
ответ дан 6 December 2019 в 21:08
поделиться