EnterLib ObjectBuild vs Castle WindsorContainer

 

首先来看一下在Castle项目中用于示范其Ioc功能的一个小例子:



   
1:  public interface IEmailSender
   
2:  {
   
3:      void Send(String from, String to, String message);
   
4:  }

   
5:   
   
6:  public interface ITemplateEngine
   
7:  {
   
8:      String Process(String templateName);
   
9:  }

  
10:   
  
11:  public interface INewsletterService
  
12:  {
  
13:      void Dispatch(String from, String[] targets, String message);
  
14:  }

  
15:   
  
16:  public class SmtpEmailSender : IEmailSender
  
17:  {
  
18:      private String _host;
  
19:      private int _port;
  
20:   
  
21:      public SmtpEmailSender(String host, int port)
  
22:      {
  
23:          _host = host;
  
24:          _port = port;
  
25:      }

  
26:   
  
27:      public virtual void Send(String from, String to, String message)
  
28:      {
  
29:          Console.WriteLine("Sending e-mail from {0} to {1} with '{2}'"
  
30:              from, to, message );
  
31:      }

  
32:  }

  
33:   
  
34:  public class NVelocityTemplateEngine : ITemplateEngine
  
35:  {
  
36:      public virtual String Process(String templateName)
  
37:      {
  
38:          return "Some template content";
  
39:      }

  
40:  }

  
41:   
  
42:  public class SimpleNewsletterService : INewsletterService
  
43:  {
  
44:      private IEmailSender _sender;
  
45:      private ITemplateEngine _templateEngine;
  
46:   
  
47:      public SimpleNewsletterService
  
48:          (IEmailSender sender, ITemplateEngine templateEngine)
  
49:      {
  
50:          _sender = sender;
  
51:          _templateEngine = templateEngine;
  
52:      }

  
53:   
  
54:      public void Dispatch(String from, String[] targets, String message)
  
55:      {
  
56:          String msg = _templateEngine.Process(message);
  
57:   
  
58:          foreach(String target in targets)
  
59:          {
  
60:              _sender.Send(from, target, msg);
  
61:          }

  
62:      }

  
63:   
  
64:  }


Ioc的作用就是能够利用容器自动的构建出一个SimpleNewsletterService对象,而不是由用户直接的创建并传递其参数,这样就可以进一步降低对象与对象之间耦合程度,从而方便的替换其实现。在上例中将采用构造器设值的方式,来实现对象依赖关系的注入。下面给出Castle的实现方式:

BasicUsage.xml
<?xml version="1.0" encoding="utf-8" ?> 
<configuration>
    
<components>
        
<component id="smtpemailsender">
            
<parameters>
                
<host>localhost</host>
                
<port>110</port>
            
</parameters>
        
</component>
    
</components>
</configuration>



   
1:  public static void Main()
   
2:  {
   
3:      IWindsorContainer container = 
   
4:      new WindsorContainer( new XmlInterpreter("../BasicUsage.xml") );
   
5:   
   
6:      container.AddComponent( "newsletter"
   
7:          typeof(INewsletterService), typeof(SimpleNewsletterService) );
   
8:      container.AddComponent( "smtpemailsender"
   
9:          typeof(IEmailSender), typeof(SmtpEmailSender) );
  
10:      container.AddComponent( "templateengine"
  
11:          typeof(ITemplateEngine), typeof(NVelocityTemplateEngine) );
  
12:   
  
13:      String[] friendsList = new String[] "john""steve""david" };
  
14:   
  
15:      // Ok, start the show
  16:   
  
17:      INewsletterService service = 
  
18:          (INewsletterService) container["newsletter"];
  
19:      service.Dispatch("hammett at gmail dot com",
  
20:                                friendsList, "merryxmas");
  
21:  }


不断向容器中加入各种类型的对象,加入过程中容器自动建立起它们之间的依赖关系,最后当我们从容器取出对象的时候,就是已经配置好依赖关系的对象。以上就是Castle的工作模式,不过Castle中的配置过程过于透明,在你完全意料不到的情况下,对象的依赖关系就按照对象被注入容器的先后顺序被设定了。非常的自动,非常的透明带来的就是某些时候的莫名奇妙。

再来看看ObjectBuild的实现方式,首先你需要通过属性(Attibute)或者配置文件的方式显式的设定依赖关系:


  
42:  public class SimpleNewsletterService : INewsletterService
  
43:  {
  
44:      private IEmailSender _sender;
  
45:      private ITemplateEngine _templateEngine;
  
46:   
  
47:      public SimpleNewsletterService(
  
48:              [Dependency(CreateType = typeof(SmtpEmailSender))]
  
49:              IEmailSender sender, 
  
50:              [Dependency(CreateType = typeof(NVelocityTemplateEngine))] 
  
51:              ITemplateEngine templateEngine)
  
52:      {
  
53:          _sender = sender;
  
54:          _templateEngine = templateEngine;
  
55:      }

  
56:   
  
57:      public void Dispatch(String from, String[] targets, String message)
  
58:      {
  
59:          String msg = _templateEngine.Process(message);
  
60:   
  
61:          foreach(String target in targets)
  
62:          {
  
63:              _sender.Send(from, target, msg);
  
64:          }

  
65:      }

  
66:   
  
67:  }
 
 

然后再利用Build直接的构造出对象

public static void Main(string[] args)
{
    
string config = string.Format(
      
@"<object-builder-config xmlns='pag-object-builder'>
        <build-rules>
            <build-rule type='{0}' mode='Singleton'>
              <mapped-type type='{1}'/>                            
              <constructor-params>
                 <value-param type='System.String'>localhost</value-param>
                 <value-param type='System.Int32'>110</value-param>
              </constructor-params>
            </build-rule>
         </build-rules>
        </object-builder-config>
", FullNameIEmailSender, FullNameSmtpEmailSender);

    Builder builder 
= new Builder(ObjectBuilderXmlConfig.FromXml(config));
    Locator locator 
= CreateLocator();

    INewsletterService newsletterService 
=
       builder.BuildUp
<SimpleNewsletterService>(locator, nullnull);

    String[] friendsList 
= new String[] "john""steve""david" };

    
// Ok, start the show

    newsletterService.Dispatch(
"hammett at gmail dot com",
                                  friendsList, 
"merryxmas");
}


从以上我们可以看出
1.  ObjectBuild和Sping类似,需要显式指定依赖关系,不过多出通过Attribute来指定的方式,而Castle则依赖于特定的对象注入顺序。可以说各有优缺点,但是我prefer前者,安全第一。(Castle也提供了在配置文件中显式指定的方式。)
2.  ObjectBuild支持直接创建临时对象,而不注入容器。(注意在上面的代码中我们仅仅BuildUp了SimpleNewsletterService,而没有象Castle那样还要将SimpleNewsletterService所依赖的对象也注入容器。)其实在OB中你可以选择是否将对象注入容器,通常情况下Singleton类型的对象才被注入容器。
3.  相对与Castle容器的概念,ObjectBuild如同它的名字所示,更象是一个构建器,你可以通过它来构建任意的对象,这些对象可能会被注入容器,也可能仅仅是一个临时对象,不过在对象的创建过程中你可以加入很多的控制,让它更符合你的需求。
4. 相对而言Castle Ioc的使用更加简洁,而ObjectBuild更加复杂一些(其实比较它们构建对象所需要的语句,OB需要的更少,只是OB的API还不够简洁,需要再做些包装),不过ObjectBuild的定制扩展能力也是相当强大,比如以上通过配置文件和属性(Attribute)结合的配置方式,完全可以通过OB中提供的API搞定,下面就是采用全编程方式的实现:
    
public static void Main()
    
{

        Builder builder 
= new Builder();
        Locator locator 
= CreateLocator();
        
        builder.Policies.SetDefault
<ISingletonPolicy>(new SingletonPolicy(true));
        
        ConstructorPolicy policy 
= new ConstructorPolicy();
        policy.AddParameter(
new ValueParameter<string>("localhost"));
        policy.AddParameter(
new ValueParameter<int>(110));

        builder.Policies.Set
<ICreationPolicy>
            (policy, 
typeof(SmtpEmailSender), null);
        builder.Policies.Set
<ITypeMappingPolicy>
            (
new TypeMappingPolicy(typeof(SmtpEmailSender), null), 
             
typeof(IEmailSender), null);

        builder.Policies.Set
<ITypeMappingPolicy>
            (
new TypeMappingPolicy(typeof(NVelocityTemplateEngine), null), 
             
typeof(ITemplateEngine), null);

        ConstructorPolicy policy2 
= new ConstructorPolicy();
        policy2.AddParameter(
new CreationParameter(typeof(IEmailSender)));
        policy2.AddParameter(
new CreationParameter(typeof(ITemplateEngine)));
        builder.Policies.Set
<ICreationPolicy>
            (policy2,
typeof(SimpleNewsletterService),null); 


        INewsletterService newsletterService 
=
             builder.BuildUp
<SimpleNewsletterService>(locator, nullnull);
      
        String[] friendsList 
= new String[] "john""steve""david" };

        
// Ok, start the show

        newsletterService.Dispatch(
"hammett at gmail dot com"
                                   friendsList, 
"merryxmas");
    }


5. Castle Ioc和ObjectBuild都支持属性设值(Property Setter)的注入方式,在此不再举例。

posted @ 2008-05-21 15:05  李占卫  阅读(441)  评论(0编辑  收藏  举报