2008-12-16 53 views
4

当您使用工厂模式时,如何在运行时注入依赖到构造函数中?你如何在工厂实现构造函数注入?

我正在构建不同格式的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(); 
    } 
} 

即使这样,他们需要从我的抽象工厂获得一个工厂的特定语境。

我专门构建的Foo在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()上做一堆重载。

那么如何将自定义值列表传入factory.BuildFoo <T>()调用来自HtmlFooConsumer.DoSomeFoo()?任何想法,stackoverflow大师?

+0

在这样复杂的问题,它真的有助于有一个更真实的例子 - 而不是一堆Foo-ey。 – Bryan 2008-12-17 15:37:38

回答

2

也许你可以沿着这些方向做些什么,你的抽象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

非常好,安德鲁。我试过了,我喜欢结果。由于消费者需要知道TArg是什么,因此我牺牲了公共API中的一些可发现性。但我认为这是一个很好的折衷灵活性。 – dalesmithtx 2008-12-18 13:49:22

+0

我很高兴你喜欢它:] – 2008-12-18 14:15:43

0

工厂基本上是静态变量的面向对象版本。我会避免使用一个。不要强迫客户使用工厂,也许只需将对象注入其构造函数中,即可避开工厂需求。

相关问题