对于IoC,第一次接触这个概念在当初学Spring的时候,当时觉得这种设计真是合理,使用IoC我们就能将我们创建的对象管理起来,而不必在对象间手动传来传去还要自己维护。使用Spring更能增强我们对denpendency relation的理解。
Ioc英文为 Inversion of Control,即反转模式,后被大牛Martin Fowler改名为 Dependency Injection 依赖注入,就是将组件之间的关系通过第三方进行注射,不需要类自己在代码中去使用Get/Set解决调用关系。
今天我们模拟写一个IoC。通过配置文件来进行组件注册。
先看看流行的.NET下几种优秀IoC
Castle:(官方站点http://www.castleproject.org/)
说明 | 不使用配置文件,容器使用的是一个第三方的组件:Windsor。由容器自动管理组件之间的依赖关系,但使用框架这不容易控制组件间的依赖关系 |
Spring.Net(Spring官方站点http://www.springframework.net/)
说明 | 由java平台上的Spring移植过来,在java平台上有大量拥护者和学习资源,都可以为.net所用。并且现在的spring可以使用注解(java里叫Annotation,类似于类似.net中的Attribute)以减少配置文件的负担。 |
Unity(CodePlex页面http://www.codeplex.com/unity)
说明 | 来自微软的Practise & Pattern团队,是Enterprise Library中的一个应用程序块。轻量级,可扩展。 |
相关资料:http://www.kaiyuan8.org/Article/UyyIMwNiXBYThOIhEvaU.aspx;http://www.codeplex.com/unity
如下就是我们这个demo级的IoC整体设计
IApplicationContext想用户提供使用IoC的接口,它本身继承IContext。
IContext用于存储每个上下文信息和注册的组件。
IRegister(组件注册器)用于向组件注入值,每个注册器中都有一个CurrentContext,当上下文获得注册器时会自动配置此值。同时含有一个IObjectInjector组件用注入。
IResourceManager用于读取配置信息,含有一个IReadAdapter,顾名思义,这是一个适用于各种存储方式的读取适配器接口,比如xml文件,或者是调用远程服务等,不管数据是怎么获得到的,最终对外都提供为XML数据。
配置文件:根节点为Goh(正式的应该加上namespace和xsd文件),每个组件的元素叫Component,Component有name和type属性,还有<Property>子元素用来表示对象中的属性(Property),每个Property元素有name、value、ref三种属性。ref可以用来引用Component。
主要接口定义
public interface IContext public interface IRegister public interface IConfigureManager public interface IReadAdapter |
实现代码
public class ConfigureManager : IConfigureManager #region Constructors & Initializer #region IConfigureManager 成员 public void ConfigContext(IContext context) #endregion #region private Helper Methods foreach(XElement elmt2 in components) public class Context : IContext #region Constructors & Initializer public Context(IRegister register) private void Init() private void InitRegisterProperty(IRegister register) #region Properties public IRegister Register public Guid ContextId #endregion public class DefaultRegister : IRegister #region Constructors & Initializer } #region IRegister 成员 public void InjectProperty(string targetName, string propertyName, object property, BindingFlags bindingFlags) private IObjectInjector Injector public class ObjectInjector : IObjectInjector public void InjectProperty(object target, string propertyName, object property, BindingFlags bindingFlags) public class TypeInitializer private void Init() #region Fields public object CreateInitObject(Type type) public int TransformStringToInteger(string prop) #region private Helper Methods public class XmlReadAdapter : IReadAdapter #region Constructors & Initializer #region IReadAdapter 成员 public System.Xml.Linq.XElement Config #endregion |
具体实现代码放到SkyDrive上了,http://qpt2ua.blu.livefilestore.com/y1pJn0xE1aDEE8kAITcT2LgpbjUTX_zjtBTJgyvdHP7Pr1iOV686i8Zu_y-koSE4mZcsrz2YRzx5S-slFOWQPdDloScCFi2MSgw/Demo_IoC.rar?download(不过里面还夹杂了点别的project。。。)
配置文件示例:
Goh.xml
<?xml version="1.0" encoding="utf-8" ?>
<GhRoot>
<Component name="register" type="GlobalHander.Register.DefaultRegister, GlobalHandler.Context.Impl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<Property name="CurrentContext" ref="applicationContext" />
<Property name="Injector" ref="objectInjector" />
</Component>
<Component name="applicationContext" type="GlobalHandler.Context.Context, GlobalHandler.Context.Impl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<Property name="Register" ref="register" />
</Component>
<Component name="objectInjector" type="GlobalHandler.Register.ObjectInjector, GlobalHandler.Context.Impl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</GhRoot>
GohComponent.xml
<?xml version="1.0" encoding="utf-8" ?>
<GhRoot>
<Component name="entityA" type="TeamTest.Entity, TeamTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<Property name="a" value="wJiang" />
<Property name="b" value="124" />
</Component>
<Component name="entityB" type="TeamTest.Entity, TeamTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<Property name="a" value="wJiang" />
<Property name="b" value="124" />
</Component>
<Component name="entityWrapper" type="TeamTest.Entity2, TeamTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<Property name="entity" ref="entityA" />
</Component>
<Property name="entity" ref="entityB" />
</Component>
</GhRoot>