Как вы внедряете инжектор конструктора на фабрике? - PullRequest
4 голосов
/ 17 декабря 2008

Когда вы используете фабричный шаблон, как вы вводите зависимости в конструкторы во время выполнения?

Я создаю Foos с различными форматами - логическим, массивом, свободным текстом, матрицей и т. Д. Этот список форматов будет расти, поскольку мы находим различные варианты использования Foo. Вот мой основной основной домен:

public interface IFoo
{
    FooFormat Format { get; }
}

public class Foo : IFoo
{
    private FooFormat _format;

    internal Foo(FooFormat format)
    {
        _format = format;
    }

    public FooFormat Format { get { return _format; } }
}


public abstract class FooFormat
{
}

public class DefaultFooFormat : FooFormat
{
}

public class BooleanFooFormat : FooFormat
{
    public IList<bool> Values { get; set; }
}

public class ArrayFooFormat : FooFormat
{
    private IList<string> _values;

    public ArrayFooFormat(IList<string> values)
    {
        _values = values;
    }

    public IList<string> Values { get { return _values; } }
}

IFoo оформлен для потребительского контекста:

public abstract class FooDecorator : IFoo
{
    private IFoo _foo;

    protected FooDecorator(IFoo foo)
    {
        _foo = foo;
    }

    public FooFormat Format
    {
        get { return _foo.Format; }
    }

    protected IFoo foo
    {
        get { return _foo; }
    }
}

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

public abstract class FooFactory
{
    protected IFoo Build<T>()
    {
        FooFormat format = GetFormat<T>();
        return new Foo(format);
    }

    private FooFormat GetFormat<T>()
    {
        if (typeof(T) == typeof(ArrayFooFormat)) return new ArrayFooFormat(new List<string>());
        if (typeof(T) == typeof(BooleanFooFormat)) return new BooleanFooFormat();
        return new DefaultFooFormat();
    }
}

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

Я специально собираю foos в HTML-контексте, например:

public class HtmlFoo : FooDecorator
{
    public HtmlFoo(IFoo foo) : base(foo) { }

    public string ToHtml()
    {
        return "<div>" + this.Format.ToString() + "</div>";
    }
}


public class HtmlFooFactory : FooFactory
{
    public IFoo BuildFoo<T>()
    {
        IFoo foo = Build<T>();
        return new HtmlFoo(foo);
    }
}

public class HtmlFooConsumer
{
    public void DoSomeFoo()
    {
        var factory = new HtmlFooFactory();
        var htmlBooleanFoo = factory.BuildFoo<BooleanFooFormat>();
        var htmlArrayFoo = factory.BuildFoo<ArrayFooFormat>();
    }
}

Моя проблема в моем абстрактном FooFactory: я всегда внедряю пустой список значений в мой ArrayFooFormat. Я хочу быть в состоянии передать список значений от потребителя. Для других FooFormats я хочу передать правильные аргументы конструктора от потребителя. Но я хочу сохранить публичный API простым - я не хочу кучу перегрузок в BuildFoo ().

Итак, как мне передать пользовательский список значений на фабрику. Вызов BooildFoo () из HtmlFooConsumer.DoSomeFoo ()? Любые идеи, гуру stackoverflow?

Ответы [ 2 ]

2 голосов
/ 17 декабря 2008

Возможно, вы можете сделать что-то в этом направлении, когда ваш абстрактный FooFormat становится IFooFormat, а универсальный FooFormat предоставляет метод Init, который получает параметр.

Тогда одна перегрузка Build позволяет передать параметр.

public interface IFooFormat
{
}

public class FooFormat<TValue> : IFooFormat
{
    private TValue _value;

    public void Init(TValue value)
    {
        _value = value;
    }

    public TValue Value
    {
        get { return _value; }
    }
}

public class ArrayFooFormat : FooFormat<IList<string>> { }

public class BooleanFooFormat : FooFormat<bool> { }

public class DefaultFooFormat : IFooFormat { }

public interface IFoo { }

public class Foo : IFoo
{
    private IFooFormat _format;

    internal Foo(IFooFormat format)
    {
        _format = format;
    }

    public IFooFormat Format { get { return _format; } }
}

public class FooFactory
{
    protected IFoo Build<TFormat, TArg>(TArg arg) where TFormat : FooFormat<TArg>, new()
    {
        TFormat format = new TFormat();
        format.Init(arg);
        return new Foo(format);
    }

    protected IFoo Build<TFormat>() where TFormat : IFooFormat, new()
    {
        return new Foo(new TFormat());
    }
}
0 голосов
/ 18 декабря 2008

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

...