使用Builder模式来初始化Bean

来源:互联网 发布:新手美工 编辑:程序博客网 时间:2024/04/30 06:07
这是写给项目组小伙伴培训用的文档。 

一、使用setXXX来配置Bean的问题

如果在spring中采用xml来配置,需要bean中提供setXXXX方法来做bean参数的注入,比如: 

Class Foo {
         PublicvoidsetName(string name) {};
         PublicvoidsetThreadCount(intcount){};
}

这方式带来的问题是,setXXX和真正开始执行业务逻辑的代码之间往往有调用先后的要求,比如 Foo会根据ThreadCount来设置要启动的Thread个数:

Foo::execute(){
这里根据Threadcount 确定启动多少个线程;
}

考虑这个代码的执行:

Foo foo = newFoo();
foo.setName(xxxx);
foo.setThreadCount(5);
foo.execute()//启动了5个线程;
foo.setThreadCount(100);//这个方法调用后,会有什么副作用?

所以,针对这个问题,现在一般使用builder模式,来将Bean初始化和Bean的业务逻辑执行分离。

二、使用Builder模式

Builder模式将类的配置和执行分离。对于只写的参数,放在builder中处理; 对于控制业务流程,并可以动态修改的参数,可以在原类中处理:

Class Foo{
   publicclass static Builder{
       privateString name;
       privateint count;
       publicBuilder name(String name){this.name = name; returnthis;};
       publicBuilder threadCount(intcount){this.count = count; returnthis;};
       publicFoo build(){ returnnew Foo(this);}
   }
  privateBuilder builder;
  publicstatic newBuilder(){
    returnnew Builder();
  }
  privateFoo(Builder builder){
         this.builder = builder;
  }
 publicvoid execute(){
     .....
     newThreadExecutor(builder.count);
 }
}

注意:

  1. Foo, Foo.Builder的构造函数不能是public的,避免被直接调用; 
  2. Builder的构造函数也不能是public,避免直接调用; 
  3. Builder的所有方法必须返回this,用来支持接连调用,如builder.name(xxx).threadcount(xxx).build();
  4. Foo中可以直接使用builder的属性; 

三、 Builder如何支持类继承

如上所示,考虑如下类结构:

classBar extend Foo{
     publicclass static BarBuilder extend Builder{
           publicBarBuilder age(intage){this.age=age;returnthis};
    }
    publicBar build(){returnnew Bar(this);}
   }
   publicstatic newBuilder(){
     returnnew BarBuilder();
   }
}

那么在构造Bar的时候,就出问题了:Bar.newBuilder().name(xxxx).age(12)

name()方法的返回值是Builder,不是BarBuilder, Builder是没有age方法的,所以调用Builder::age,就出现编译错误。 

解决方法是使用模板类, Foo定义修改为:

Class Foo{
   publicclass static Builder<T extendsBuilder<T>>{
       privateString name;
       privateint count;
       publicT name(String name){this.name = name; return(T)this;};
       publicT Builder threadCount(intcount){this.count = count; return(T)this;};
       publicFoo build(){ returnnew Foo(this);}
   }
  privateBuilder<?> builder;
  publicstatic newBuilder(){
    returnnew Builder();
  }
  privateFoo(Builder<?> builder){
         this.builder = builder;
  }
 publicvoid execute(){
     .....
     newThreadExecutor(builder.count);
 }
}

 

Bar定义修改为:

Class Bar{
   publicclass static BarBuilder extendsBuilder<BarBuilder>{
       privateint age;
      
       publicBarBuilder age(intage){this.age = age; returnthis;};
       publicBar build(){ returnnew Bar(this);}
   }
  privateBarBuilder builder;

 

这样,使用Bar.newBuilder(). name (xxxx).age(12) ,就没问题了。 

0 0
原创粉丝点击