[英]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.