Castle学习笔记之Windsor(一)

Castle大名早就如雷贯耳,早就想研究一下,无奈公司项目一直比较紧迫,直到前天BOSS告诉我该转入下一部分框架的设计工作了,嘿嘿,刚好借这个机会,开始我的Castle之旅:)

 首先向不熟悉的朋友介绍下Castle到底是什么.Castle是.net平台上的一个开源项目,为企业级开发和WEB应用程序开发提供完整的服务.当前开发的许多流行元素,比如IOC,ORM都在Castle上有非常成熟的应用.http://www.castleproject.org是其官方站点,你可以在上面了解更多有关Castle的信息.点击此处立刻下载sample和source的完整安装包.

Windsor是Castle下的一个项目,用于提供IOC的解决方案.IOC被称为控制反转或者依赖注入(Dependency Injection).关于它的严格定义和解释可以参照大师的文章http://martinfowler.com/articles/injection.html  . 我的解释就是,IOC的目的就是用于对象间的解耦,把对象之间的依赖关系延迟注入.

稍有经验的开发者都已经开始习惯于基于接口或者抽象类的编程,当我们想要创建一个对象时,我们通常会为其建立一个接口,哪怕从这个接口再派生对象的可能性非常小.这最大的好处当然是高扩展性,我们永远不知道客户的需求会怎么变化,为了适应需求的变化,我们只能希望每次变化不会带来过长的链式反应和类的爆炸式增长.以我目前的项目为例子:我需要创建一个缓存管理的程序,按照上头的意思,将采用MS的企业库来对缓存进行处理,那么我首先需要对外暴露一个CacheManger的类,为简单起见,我这个类只有一个方法GetData().这个方法并不实际执行什么操作,它将调用CacheEngine里的方法来取出具体的缓存的值,但是CacheEngine的方法需要一个额外的参数,key,这个key值我们将从另一个类CacheConfig里取出.调用很简单:CacheManger->CacheEngine&CacheConfig.

相信没有程序员会这么做,我们一定会建立ICacheEngine和ICacheConfig接口,同时各自派生一个MyCacheEngine和MyCacheConfig类,当需求有变化时,比如我们又被要求以System.Web.Cacheing或者Enterprise Service的方式进行缓存的处理时,我们立刻会从ICacheEngine里派生新的类,而无须修改之前的类,遵循了开闭原则.

长久以来,很多程序员都这么做(包括我自己),而且这么做本身没有什么错.不过我们必须认识到,在这种模式下,对象间的依赖是无法解除的.在这里,CacheManager里的GetData方法不仅依赖于ICacheEngine和ICacheConfig接口,同时还依赖于它们的具体实现—MyCacheEngine和MyConfig.这就是问题的所在:对象间的耦合!

这里我并不极端的认为要追求绝对的松耦合,实际上那也是不现实的,即使是IOC也不过是延迟了对象的关联,关键问题是:我们能否消除此处的耦合关系?
答案是肯定的,当然这里的消除也是将耦合移到外部,并不是真正的清除.接下来让我们看看在Windsor里是如何做到这一点的.

依然是上面的例子,我们先为其添加需要的接口.
ICacheConfig:

None.gif namespace  WindsorTest.Interface
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
interface ICacheConfig
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
string GetCacheKey();
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

ICacheEngine:
None.gif namespace  WindsorTest.Interface
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
public interface ICacheEngine
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
string GetCacheData(string key);
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

ICacheManager:
None.gif namespace  WindsorTest.Interface
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
interface ICacheManager
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
string GetData();
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}


接下来开始创建接口们的具体实现:

MyConfig

None.gif namespace  WindsorTest.Components
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
class MyConfig : ICacheConfig
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif
InBlock.gif        
public MyConfig()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
ExpandedSubBlockEnd.gif        }

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
ICacheConfig Members#region ICacheConfig Members
InBlock.gif
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 获取缓存数据的key值
InBlock.gif        
/// </summary>
ExpandedSubBlockEnd.gif        
/// <returns></returns>

InBlock.gif        public string GetCacheKey()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
return "key";
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

MyCacheEngine
None.gif namespace  WindsorTest.Components
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
class MyCacheEngine : ICacheEngine
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ContractedSubBlock.gifExpandedSubBlockStart.gif        
ICacheEngine Members#region ICacheEngine Members
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 创建一个CacheEngine实例
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="key">key值</param>
ExpandedSubBlockEnd.gif        
/// <param name="value">数值</param>

InBlock.gif        public MyCacheEngine(string key,string value)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            CacheManager cm 
= CacheFactory.GetCacheManager();
InBlock.gif            cm.Add(key, value);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 获取指定key值的cache
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="key"></param>
ExpandedSubBlockEnd.gif        
/// <returns></returns>

InBlock.gif        public string GetCacheData(string key)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            CacheManager cm 
= CacheFactory.GetCacheManager();
InBlock.gif            
if (cm.GetData(key) == null)
InBlock.gif                cm.Add(key, key);
InBlock.gif            
return cm.GetData(key).ToString() ;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

MyCacheManager
None.gif namespace  WindsorTest.Services
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
class MyCacheManager : ICacheManager
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ContractedSubBlock.gifExpandedSubBlockStart.gif        
construct&members#region construct&members
InBlock.gif
InBlock.gif        
private ICacheEngine _engine;
InBlock.gif        
private ICacheConfig _config;
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 构造CacheManager
InBlock.gif        
/// </summary>
InBlock.gif        
/// <param name="engine"></param>
ExpandedSubBlockEnd.gif        
/// <param name="config"></param>

InBlock.gif        public MyCacheManager(ICacheEngine engine, ICacheConfig config)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            _engine 
= engine;
InBlock.gif            _config 
= config;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
ContractedSubBlock.gifExpandedSubBlockStart.gif        
ICacheManager Members#region ICacheManager Members
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 获取数据
InBlock.gif        
/// </summary>
ExpandedSubBlockEnd.gif        
/// <returns></returns>

InBlock.gif        public string GetData()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
string key = _config.GetCacheKey();
InBlock.gif            
return _engine.GetCacheData(key);
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

到此,我们的大部分代码结束了,不过大概许多朋友还没看出来这与普通的接口编程有什么区别?呵呵,确实如此,到现在为止依然与之前的做法没有两样,那是因为关键的调用还没有开始.通常,我们也许会写下下面的代码来结束这个程序.
None.gif ICacheManager manger  =   new  MyCacheManager( new  MyCacheEngine( " key " " value " ),  new  MyConfig());
None.gif            manager.GetData();

瞧,我们需要三个构造过程,而且我们必须清楚每个构造函数里面的参数是什么意思,我们只是想要从缓存里读个值,居然要了解这么多的事??
看看我们的Windsor是如何来解决这个问题的吧.

None.gif static   void  Main( string [] args)
ExpandedBlockStart.gifContractedBlock.gif        
dot.gif {
InBlock.gif            IWindsorContainer container 
= new WindsorContainer(new XmlInterpreter("../../config.xml"));
InBlock.gif            container.AddComponent(
"manager"typeof(ICacheManager), typeof(MyCacheManager));
InBlock.gif            container.AddComponent(
"config"typeof(ICacheConfig), typeof(MyConfig));
InBlock.gif            container.AddComponent(
"engine"typeof(ICacheEngine), typeof(MyCacheEngine));
InBlock.gif
InBlock.gif            ICacheManager manager 
= (ICacheManager)container["manager"];
InBlock.gif            Console.Write(manager.GetData());
InBlock.gif            Console.ReadLine();
InBlock.gif            
//ICacheManager manger = new MyCacheManager(new MyCacheEngine("key", "value"), new MyConfig());
InBlock.gif            
//manager.GetData();
ExpandedBlockEnd.gif
        }

分析一下这段代码,首先,我们需要一个IOC容器,并指定配置文件(这个稍后再说).然后挨个注册我们用到了的三个接口的实现(这里也有许多的注册方式,也稍后再说).接下来,我们从容器里取出我们需要的CacheManager,执行它.看看里面,没有一个对象的实例化行为(除了容器),三个对象间的依赖完全消失了!当然,这个样子是不能立刻运行的,我们还需要添加一个小小的配置文件.
None.gif <? xml version="1.0" encoding="utf-8"  ?>
None.gif
< configuration >
None.gif  
None.gif  
< components >
None.gif    
< component  id ="engine" >
None.gif      
< parameters >
None.gif        
< key > key </ key >
None.gif        
< value > key-value </ value >
None.gif      
</ parameters >
None.gif    
</ component >
None.gif  
</ components >
None.gif  
None.gif  
</ configuration >

哈,运行下,看看?没问题,接下来我再来解释下为何这里就能简单的解决对象间的依赖关系.你可以把每次的注册看做一次对象的实例化,但是这个过程我们并不需要指定任何参数,而对象的引用也都是智能的实现,当然这里面有一定的规则在里面,在下一篇文章里,我将再来更深入的谈谈注册的方式和构造注入是如何实现的.

下班时间到了,回去咯,我会抽时间尽快的开始我的该系列的第二篇^_^.
注:本人也是以学习和研究的态度来写这篇文章,里面的许多观点只代表我的个人思想,加之研究Windsor尚浅,里面必然有许多不当之处,还请各位看官多多包涵:)

参考文献:
Introducing Castle 
Inversion of Control Containers and the Dependency Injection pattern
Ioc模式
Castle IOC容器快速入门

转载于:https://www.cnblogs.com/wuxilin/archive/2006/04/20/380475.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值