2014-11-09 51 views
2

我有用於構建項目的構建器 - 導演實現。應該使用哪種模式來確定用於項目的構建器?

public void main(ItemKey itemKey) { 
    Director aDirector = new Director(); 

    ItemBuilderFactory itemBuilderFactory = new ItemBuilderFactory(); 
    var builder = itemBuilderFactory.GetBuilderFor(itemKey); //<--- How to do this? 

    aDirector.Construct(builder, itemKey); 

    Console.WriteLine(builder.Item.BusinessName); 
    Console.WriteLine(builder.Item.CustomerName); 
    Console.WriteLine(builder.Item.AdvancedName); 
} 

public class Director { 
    public void Contruct(IItemBuilder builder, ItemKey itemKey) { 
     builder.CreateItem(); 
     builder.GetBusinessItemInformation(itemKey); 
     builder.GetCustomerItemInformation(itemKey); 
     builder.GetAdvancedItemInformation(itemKey); 
    } 
} 

public interface IItemBuilder { 
    Item Item { get; } 
    void GetBusinessItemInformation(ItemKey itemKey); 
    void GetCustomerItemInformation(ItemKey itemKey); 
    void GetAdvancedItemInformation(ItemKey itemKey); 
    bool CanBuild(ItemKey itemKey); // I don't like this and I think it violates SRP. Forces me to retrieve info about the item, then determine if the builder can build it, and return a flag indicating it. 
    void CreateItem(); 
} 

public class ItemBuilderFactory { 
    private readonly List<IItemBuilder> _builders; 
    public ItemBuilderFactory(List<IItemBuilder> builders) { 
     _builders = builders; 
    } 
    public IItemBuilder GetBuilderFor(ItemKey itemKey) { 
     //What do I do here? Current impl: 
     return _builders.Single(builder => builder.CanBuild(itemKey)); //huge red flag, just a fancy if 
    } 
} 

public class ItemKey { 
    public int Upc {get;set;} 
    public string ItemCode {get;set;} 
} 

我儘量避免使用if語句,但是這似乎是我可能需要的時候。我還能怎樣「讓建造者能夠建造這個物品」?我曾想過創建某種映射類,但是這會嚴重增加查看代碼的認知開銷,並且可能有人會將我推向正確的方向。

回答

0

每Sebastion彪的回答,鍵入到項目本身的特定屬性的字典是方向我但是,Sebastion的回答將需要爲每個項目鍵添加一個新的構建器,當項目構建者真正對基於int屬性的項目做出不同反應時,項目關鍵字只會有三個可能的值時刻。

static void main() {  
    var itemKey = new ItemKey {Upc = 11124}; 

    var builderKeyDataService = new BuilderKeyDataService(); 
    var builderKey = builderKeyDataService.GetBuilderKey(itemKey); //get the map key (an int) however you would do so, in my case it would be a database call 

    var itemBuilders = new Dictionary<int, IItemBuilder>(); 
    itemBuilders.Add(12, new RegularItemBuilder()); 
    itemBuilders.Add(11, new SpecialItemBuilder()); 
    itemBuilders.Add(1, new RegularItemBuilder()); 
    var itemBuilderMap = new ItemBuilderMap(itemBuilders); //this would be dependency injected normally 

    var builder = itemBuilderMap.GetBuilderFor(builderKey); 

    var aDirector = new Director(); 
    aDirector.Construct(builder, itemKey); 

    Console.WriteLine(builder.Item.BusinessName); 
    Console.WriteLine(builder.Item.CustomerName); 
    Console.WriteLine(builder.Item.AdvancedName); 
} 

public class ItemBuilderMap 
{ 
    private readonly Dictionary<int, IItemBuilder> _mapList; 

    public ItemBuilderMap(Dictionary<int, IItemBuilder> mapList) 
    { 
     _mapList = mapList; 
    } 

    public IItemBuilder GetBuilderFor(int builderKey) 
    { 
     if(_mapList.ContainsKey(builderKey) { 
      return _mapList[builderKey]; 

     throw new KeyNotFoundException(); 
    } 
} 
1

您可以使用IOC和依賴項注入將項目鍵映射到IItemBuilder實現 - 只需在構建您決定使用的任何IOC容器(Ninject,Unity等)期間將itemKey映射註冊到IItemBuilders。

無論您選擇哪種技術,某個版本的if,無論是在IOC框架內,都可以保持雙手清潔,或者如果您使用反射或問題中的技巧。

1

我傾向於使用詞典進行映射,所以它看起來是這樣的:

public class ItemBuilderFactory 
{ 
    //i'm asuming you need a new instance of builder every time you call the factory, don't know if your answer below left that out in purpose or not 
    private readonly IDictionary<ItemKey, Func<IItemBuilder>> _builders = new Dictionary<ItemKey, Func<IItemBuilder>> 
    { 
     { SomeItemKey,() => new SomeItemBuilder() } 
     ... //initialise this with all your mappings. You could configure this in the constructor too etc. 

    } 

    public IItemBuilder GetBuilderFor(ItemKey key) 
    { 
     if (!_builders.ContainsKey(key)) 
      throw new Exception("No builder for provided key"); 

     //get the lambda and execute it to create a new item (assuming it has state of course) 
     return _builders[key](); 
    } 
} 
+0

對不起,我應該提供了一個itemkey的例子,請參閱已編輯的問題。 – 2014-11-10 23:04:52

+0

雖然我仍然可以使用你的實現,但它只需要一個IDictionary 2014-11-10 23:06:21

+0

是的,也只是挑剔,但是你有意爲給定的鍵返回相同的構建器實例,那麼它應該被稱爲與Factory不同的東西。 – 2014-11-10 23:30:59

相關問題