使用Builder模式来初始化Bean

本文探讨了Spring框架中Bean配置的局限性,特别是在使用set方法注入参数时的问题,并提出使用Builder模式作为解决方案。通过示例介绍了如何应用Builder模式来分离Bean的配置与执行逻辑,进一步讨论了该模式在类继承中的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是写给项目组小伙伴培训用的文档。 

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

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

Class Foo {
         Public void setName(string name) {};
         Public void setThreadCount(int count){};
}

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

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

考虑这个代码的执行:

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

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

二、使用Builder模式

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

Class Foo{
   public class static Builder{
       private String name;
       private int count;
       public Builder name(String name){this.name = name; return this;};
       public Builder threadCount(int count){this.count = count; return this;};
       public Foo build(){ return new Foo(this);}
   }
  private Builder builder;
  public static newBuilder(){
    return new Builder();
  }
  private Foo(Builder builder){
         this.builder = builder;
  }
 public void execute(){
     .....
     new ThreadExecutor(builder.count);
 }
}

注意:

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

三、 Builder如何支持类继承

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

class Bar extend Foo{
     public class static BarBuilder extend Builder{
           public BarBuilder age(int age){this.age=age; return this};
    }
    public Bar build(){return new Bar(this);}
   }
   public static newBuilder(){
     return new BarBuilder();
   }
}

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

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

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

Class Foo{
   public class static Builder<T extends Builder<T>>{
       private String name;
       private int count;
       public T name(String name){this.name = name; return (T)this;};
       public T Builder threadCount(int count){this.count = count; return (T)this;};
       public Foo build(){ return new Foo(this);}
   }
  private Builder<?> builder;
  public static newBuilder(){
    return new Builder();
  }
  private Foo(Builder<?> builder){
         this.builder = builder;
  }
 public void execute(){
     .....
     new ThreadExecutor(builder.count);
 }
}

 

Bar定义修改为:

Class Bar{
   public class static BarBuilder extends Builder<BarBuilder>{
       private int age;
      
       public BarBuilder age(int age){this.age = age; return this;};
       public Bar build(){ return new Bar(this);}
   }
  private BarBuilder builder;

 

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值