Многоуровневый рефакторинг DI - PullRequest
2 голосов
/ 20 октября 2011

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

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

Сейчас в моем проекте 43 ссылки на текущий уровень, доступ к которым осуществляется через игру, синглтон.Например, Game.CurrentGame.CurrentMap.Something.Ссылки находятся на экранах, объектах, компонентах поведения, даже в основной форме (для средств отладки).

Я хочу избавиться от этой ссылки, введя все, что нужно.Но сама CurrentMap не является желаемой зависимостью - другие вещи доступны ниже ее.Поэтому мой первоначальный план состоит в том, чтобы пойти в каждое место, найти то, что на самом деле используется, и внедрить его, добавив параметр в конструктор этого класса.Это вводит еще одну зависимость на один уровень выше, поэтому я повторяю процесс, пока все не закончится.Но проблема в том, что он введет намного больше параметров конструктора, в том числе в местах, где зависимость не используется напрямую.Многие классы получат зависимость, чтобы передать ее другому объекту под ними.

Что может быть более чистой альтернативой этому?

Ответы [ 3 ]

2 голосов
/ 20 октября 2011

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

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

Допустим, у вас есть объект a, который вызывает объект b, который вызывает объект cобъект c нуждается в текущем уровне, а объект b - нет.

Неправильный способ сделать это - вызвать new C(level); изнутри b.Как вы указали, b не нужно знать об уровне, поэтому кажется, что дела становятся хуже, а не лучше.Вы не зашли достаточно далеко с внедрением зависимости.Вместо создания c в b, просто спросите c в конструкторе b.Теперь класс b знает только о c и ничего не знает о level.

Миско объяснил это лучше, чем я могу здесь http://misko.hevery.com/2009/03/30/collaborator-vs-the-factory/

Код на заводе выглядит следующим образом:

Level level = new Level();
C c = new C( level );
B b = new B( c );
A a = new A( b );

Класс B знает только о своих непосредственных соавторах (c) и не зависит от Level.Поскольку мы создаем вещи на фабрике, нет необходимости пропускать листья графа объектов через граф объектов.

Если за создание c отвечает класс B, ему необходимознать все о том, как сделать экземпляр класса c.Это не верно.

1 голос
/ 20 октября 2011

Посмотрите на использование DI Framework, такого как Castle Windsor, Structuremap или Unity (есть и множество других, которые также вполне солидны).

Проблема, которую вы описываете, заключается не только в проблема, которую решают эти структуры, но это большая часть типа трения, которую они почти полностью устраняют.

Тот факт, что зависимости являются конкретными реализациями, а не абстракциями более высокого уровня, не имеет значения.См. Этот вопрос (искренне заданный вами):

IOC / DI: Регистрация конкретного типа является запахом кода?

0 голосов
/ 20 октября 2011

Обычно я внедряю сервис, который отслеживает текущее состояние:

public interface IGameStateTracker
{
    Game CurrentGame {get;}
    GameMap CurrentMap {get;}
}

Вам нужно только внедрить этот сервис в конструкторы классов, которые будут нуждаться в нем напрямую. Боюсь, я не до конца понимаю, почему вы обнаружили, что вам нужно вводить вещи в классы, которые в этом не нуждаются напрямую: это может быть признаком того, что вы не используете надлежащие шаблоны DI. Не могли бы вы предоставить несколько примеров кода, чтобы показать пример этой проблемы?

Я второе замечание Фила Сэндлера об использовании структуры DI. Это сделает жизнь намного проще. Но это не компенсирует использование неправильных паттернов DI.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...