Неизменные классы и блок приложения единства - PullRequest
2 голосов
/ 13 февраля 2010

Я пишу небольшую утилиту для себя, поэтому пока я использую Unity, я могу перейти на другой контейнер IoC, если это позволит мне обойти эту проблему.

Я хочу создать классэто дает некоторые данные при его создании, но после этого остается неизменным, обычно я делаю это следующим образом:

class SomeItem
{
    public SomeItem(string name)
    {
        Name = name;
        Hash = new SomeHashingClass().GenerateHash(name);
    }

    public string Name { get; private set; }

    public string Hash { get; private set; }
}

Проблема заключается в зависимости от SomeHashingClass в конструкторе, как я могу вставить его при сохранениинеизменяемый объект?

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

Другой способ, который я вижу, это создать класс SomeItemFactory, который разрешается за единицу, затем вручную сделать зависимостьвпрыск для SomeItem, однако это удваивает объем кода:

class SomeItemFactory
{
    IHashingClass _hashingClass;

    public SomeItemFactory(IHashingClass hashingClass)
    {
        _hashingClass = hashingClass;
    }

    public SomeItem Create(string name)
    {
        return new SomeItem(_hashingClass, name);
    }
}

class SomeItem
{
    public SomeItem(IHashingClass hashingClass, string name)
    {
        Name = name;
        Hash = hashingClass.GenerateHash(name);
    }

    public string Name { get; private set; }

    public string Hash { get; private set; }
}

Пожалуйста, скажите мне, что есть чистый способ сделать это.Почему нет такого метода, как:

unityContainer.Resolve<SomeItem>("the items name");

Ответы [ 3 ]

3 голосов
/ 13 февраля 2010

Хотя вы действительно можете передавать параметры в метод Resolve, тщательно продумайте, действительно ли это правильный дизайн.

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

Использование DI-контейнеров должно следовать голливудскому принципу: скажите разрешить весь граф приложений в корне композиции , а затем забудете все об этом.

В вашем конкретном случае вы можете оставить SomeItem как есть, но если вы хотите изменить HashingClass как зависимость, вам нужно внедрить его в SomeItem, а Constructor Injection - это лучший вариант.

Если вам нужен только один экземпляр SomeItem в вашем приложении, вы можете подключить его так же, как в Unity, но если вам нужно создать несколько экземпляров, Abstract Factory - правильный подход .

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

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

Обратите внимание, что ни один из этих принципов не направлен конкретно на Unity, но широко применяется к DI в целом.

0 голосов
/ 13 февраля 2010

Можно сделать как ты говоришь в единстве

unityContainer.Resolve<ISomeInterface>("MyMappingName");

В конфигурации, если вы используете файл конфигурации, вы можете иметь

<typeAliases>
    <typeAlias alias="SomeInterface" type="ISomeInterface, SomeAssembly" />
    <typeAlias alias="SomeConcreteType" type="SomeType, SomeAssembly" />
</typeAliases>

<containers>
    <container>
        <type type="SomeInterface" mapTo="SomeConcreteType" name="MyMappingName" />
    </container>
</containers>
0 голосов
/ 13 февраля 2010

Кажется, вы можете передавать параметры в метод Resolve (). Смотрите подробности в принятом ответе на этот вопрос: Могу ли я передать параметры конструктора в метод Unity Resolve ()?

...