簡體   English   中英

您如何在工廠中實現構造函數注入?

[英]How do you implement constructor injection in a factory?

使用工廠模式時,如何在運行時將依賴項注入到構造函數中?

我正在用不同的格式(布爾,數組,自由文本,矩陣等)構建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();
    }
}

即便如此,他們仍需要根據自己的特定上下文從我的抽象工廠派生一個工廠。

我專門在html上下文中構建foos,如下所示:

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中。 我希望能夠傳遞消費者的值列表。 對於其他FooFormat,我想從使用者中傳遞正確的構造函數參數。 但是我想讓公共API變得簡單-我不想在BuildFoo()上重載。

那么如何從HtmlFooConsumer.DoSomeFoo()內部將自定義值列表傳遞到factory.BuildFoo <T>()調用中? 有什么想法,stackoverflow專家嗎?

也許您可以按照以下步驟做一些事情,其中​​抽象的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());
    }
}

工廠基本上是靜態變量的面向對象版本。 我會避免一起使用。 與其強迫客戶使用工廠,不如直接將對象注入其構造函數中,而無需工廠。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM