微软objectBuilder解读:构造一个轻量级的Dependency Injection容器(2) 工厂和容器

我们利用简单工厂继续对示例进行修改为

public class CreatorFactory

{

    public static IMessageCreator GetCreator()

   {

        return new ConsoleMessageCreator();

    }

}

public class ProcessorFactory

{

    public static IMessageProcessor GetProcessor(string message)

   {

        if (message == "order") return new PrinterMessageProcessor();

        return new ConsoleMessageProcessor();

    }

}

Main里面的代码,

static void Main(string[] args)

{

    Console.WriteLine("Demo DIP ");

    IMessageCreator messageCreator = null;

    IMessageProcessor messageProcessor = null;

    messageCreator = CreatorFactory.GetCreator();           

    string s = messageCreator.Create();

    messageProcessor = ProcessorFactory.GetProcessor(s);

    messageProcessor.Process(s);

    Console.Read();

  }

现在看起来,代码有一定的扩展性,各个组件各司其职,符合高内聚低耦合的特征,如果新增加一种消息处理器类型或者消息生成器,只需要改动一个类的方法,改动不会遍及其他模块或者组件,上层应用系统得到稳定。再来看组件图。

 

那么当前代码还有么有其他问题或者改进之处呢?

1) 每增加一类接口,就要增加一个Factory类,例如要增加对消息的日志处理,就要增加一个接口IMessageLog和工厂组件LogFactory(可以用抽象工厂改进)

2) Main虽然对具体消息处理生成组件没有依赖,但是对具体工厂类增加了依赖。

解决问题的核心就是抛弃工厂和接口一一对应的建立关系,将工厂泛化,实现改进的工厂。我们给它一个新的定义---容器/Container

我们设想有这样一种万能容器(我心中的God),我们需要某种实现了特定功能(接口)的组件,就从它那里去拿。类似于main等的客户端就无需关心组件从哪里来的,也无需去了解接口和工厂的对应关系了(这也不应该由上层组件所关注),就像潘多拉的魔盒(比喻有点不恰当),你要什么有什么。

理解了Container的概念,我们很快就能思考到Container组件的主要接口应该为:

void Add(Type key, object value); //注册接口/组件

bool Remove(Type key); //注销接口/组件

object Get(Type key); //获取组件实例

bool Contains(Type key); //判断某个接口类型的组件是否存在

......

这里的Type参数很自然就是我们所需要的接口类的类型,Container的接口设计符合需求:需要实现某种接口的组件就从Container里面去拿。如果考虑泛型,那么可以再增加一些方法:

TItem Get<TItem>(); //object Get(Type key)的泛型方法

TItem Get<TItem>(Type key); //object Get(Type key)的泛型方法

细心的读者就会想到Container的数据结构一定是键/值对,接口类型为键,object类型为值了(因为有各种接口组件的实例,所以只能采用object类型来存储),在.net framework里面的Dictionary天然支持键/值对,直观的想法就可以利用Dictionary来实现我们需要的Container.

public interface IContainer

 {

        void Add(Type key, object value);

        bool Remove(Type key);

        object Get(Type key);

        bool Contains(Type key);

        TItem Get<TItem>();

        TItem Get<TItem>(Type key);

}

public class DefaultContainer:IContainer

 {

        private Dictionary<Type, object> inner = new Dictionary<Type, object>();

        //注册某个接口类型的组件实例

        public void Add(Type key, object value)

        {

            if (key == null)   throw new ArgumentNullException("key");

            if (value == null)  throw new ArgumentNullException("value");

            inner.Add(key, value);

        }

         //清除某个接口类型的组件实例

        public bool Remove(Type key)

        {

            if (key == null)  throw new ArgumentNullException("key");

            return inner.Remove(key);

        }

         //提取某个接口类型的组件实例

        public object Get(Type key)

        {

            if (key == null)  throw new ArgumentNullException("key");

            if (inner.ContainsKey(key))  return inner[key];

            return null;

        }

         //容器是否注册了包含某个接口类型的组件

        public bool Contains(Type key)

        {

            if (key == null)  throw new ArgumentNullException("key");

            if (inner.ContainsKey(key))  return true;

            return false;

        }

         //泛型方法: object Get(Type key)

        public TItem Get<TItem>()

        {

            var value=Get(typeof(TItem));

            if(value!=null)  return (TItem)value;

            return default(TItem);

        }

         //泛型方法: object Get(Type key)

        public TItem Get<TItem>(Type key)

        {

            if (inner.ContainsKey(key))  return (TItem)Get(key);

            return default(TItem);

        }

    }

Main里面的代码改为:

static void Main(string[] args)

{

      Console.WriteLine("Demo DIP");

      IContainer container = new DefaultContainer();

      container.Add(typeof(IMessageCreator), new ConsoleMessageCreator());

      container.Add(typeof(IMessageProcessor), new ConsoleMessageProcessor());

      IMessageCreator messageCreator = container.Get<IMessageCreator>();

      IMessageProcessor messageProcessor = container.Get<IMessageProcessor>();           

      string message=messageCreator.Create();

     messageProcessor.Process(message);

      Console.Read();

}

运行结果为:

 

下一章节我们要研究现在的Container的问题和微软对此的解决方案Locator.由此我们正式开始研究微软ObjectBuilder的源代码了。

 

 

posted on 2011-05-20 14:17  胡以谦  阅读(681)  评论(9编辑  收藏  举报