【设计模式】建造者模式

  |   0 评论   |   18 浏览

简介

建造者模式隐藏了创建过程,让客户端调用变的简单,使一个复杂的类可以被简单的创建,他属于创建型设计模式。他可以解决以下问题:
1、创建一个复杂的类时,他的创建顺序不一样。
2、如果让一个复杂的类创建变的简单?
如果不适用建造者模式,那么你创建一个类需要在应用层去组装这个类,这样会出现很多冗余代码,而且不灵活,建造者模式可以把这些复杂的创建过程进行封装。在Builder对象中封装了复杂的对象创建,类的创建交给Builder来完成,而不是直接创建复杂的类。建造者模式主要是将一个复杂对象的构建与它的表现分离,使得同样的构建过程可以创建不同的表现。

适用场景

1、如果一个对象有非常复杂的内部结构
2、想把复杂对象的创建和表现分离

优点

1、封装性好,创建和使用分离
2、扩展性好,建造类之间独立,一定程度上解耦,允许你修改产品内部表现

缺点

1、产生多余的Builder对象
2、要求builder类是可变的
3、类的数据成员不能保证被初始化
4、产品内部发生变化,建造者都要修改,成本较大
5、依赖注入可能不太支持

示例代码

image.png
先看下建造者的类图,示例是创造汽车的例子,来看看具体的代码:
汽车类:

public class Car {
    private String color;
    private int wheels;
    public Car() {
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    public int getWheels() {
        return wheels;
    }
    public void setWheels(int wheels) {
        this.wheels = wheels;
    }
    @Override
    public String toString() {
        return "Car{" +
                "color='" + color + '\'' +
                ", wheels=" + wheels +
                '}';
    }
}

汽车的建造者抽象类

public abstract class CarBuilder {
    public abstract void buildColor(String color);
    public abstract void buildWheels(int wheels);
    public abstract Car makeCar();
}

建造者的实现类

public class CarBuilderImpl extends CarBuilder {
    private Car car = new Car();
    @Override
    public void buildColor(String color) {
        car.setColor(color);
    }
    @Override
    public void buildWheels(int wheels) {
        car.setWheels(wheels);
    }
    @Override
    public Car makeCar() {
        return car;
    }
}

创建一个主任类,来负责进行创建:

public class CarBuilderDirector {
    private CarBuilder carBuilder;
    public void setCarBuilder(CarBuilder carBuilder){
        this.carBuilder = carBuilder;
    }
    public Car makeCar(String color,int wheels){
        carBuilder.buildColor(color);
        carBuilder.buildWheels(wheels);
        return carBuilder.makeCar();
    }
}

最后是一个测试类:

public class BuilderTest {
    public static void main(String[] args) {
        CarBuilder carBuilder = new CarBuilderImpl();
        CarBuilderDirector carBuilderDirector = new CarBuilderDirector();
        carBuilderDirector.setCarBuilder(carBuilder);
        Car car = carBuilderDirector.makeCar("红色",4);
        System.out.println(car);
    }
}

在这个例子中,出现了很多类,如主任类,Builder相关的类,那么有没有办法简化呢?
下面在来看个例子:
image.png
通过链式方式,减少了很多类。

public class Car {
    private String color;
    private int wheels;
    public Car(CarBuilder carBuilder) {
        this.color = carBuilder.color;
        this.wheels = carBuilder.wheels;
    }
    @Override
    public String toString() {
        return "Car{" +
                "color='" + color + '\'' +
                ", wheels=" + wheels +
                '}';
    }
    public static class CarBuilder{
        private String color;
        private int wheels;
        public CarBuilder buildColor(String color){
            this.color = color;
            return this;
        }
        public CarBuilder buildWheels(int wheels){
            this.wheels = wheels;
            return this;
        }
        public Car build(){
            return new Car(this);
        }
    }
}

测试类:

public class BuilderTest {
    public static void main(String[] args) {
        Car car = new Car.CarBuilder().buildColor("红色").buildWheels(4).build();
        System.out.println(car);
    }
}

第一个例子,通过传参来构建builder类,这样容易出现参数传入错误的问题,通过链式的方式,对赋值变的简单,不容易出错。
上面示例源码

源码分析

在很多源码框架中都使用了建造者模式。

jdk中应用

StringBuilderStringBuffer都有用建造者模式,如
StringBuilder的代码

@Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

StringBuffer的代码

@Override
    public synchronized StringBuffer append(Object obj) {
        toStringCache = null;
        super.append(String.valueOf(obj));
        return this;
    }

guava中应用

ImmutableSet中也使用了建造者模式,查看部分源码:

 public static class Builder<E> extends ImmutableCollection.ArrayBasedBuilder<E> {
    public Builder() {
      this(DEFAULT_INITIAL_CAPACITY);
    }
    Builder(int capacity) {
      super(capacity);
    }
    @Override
    public Builder<E> add(E element) {
      super.add(element);
      return this;
    }
    @Override
    public Builder<E> addAll(Iterable<? extends E> elements) {
      super.addAll(elements);
      return this;
    }
    @Override
    public ImmutableSet<E> build() {
      ImmutableSet<E> result = construct(size, contents);
      size = result.size();
      return result;
    }
  }
public static <E> Builder<E> builder() {
    return new Builder<E>();
  }

使用示例:

ImmutableSet set = new ImmutableSet.Builder<>().add("1").build();
System.out.println(set);

spring中应用

BeanDefinitionBuilder也是使用了建造者模式,如:

public static BeanDefinitionBuilder genericBeanDefinition() {
	BeanDefinitionBuilder builder = new BeanDefinitionBuilder();
	builder.beanDefinition = new GenericBeanDefinition();
	return builder;
}
public static BeanDefinitionBuilder rootBeanDefinition(String beanClassName) {
	return rootBeanDefinition(beanClassName, null);
}

mybatis中应用

SqlSessionFactoryBuilder也使用了建造者模式,可以创建SqlSessionFactory类,如:

public class SqlSessionFactoryBuilder {
  public SqlSessionFactory build(Reader reader) {
    return build(reader, null, null);
  }
  public SqlSessionFactory build(Reader reader, String environment) {
    return build(reader, environment, null);
  }
  public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        reader.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }
}

在mybatis中大量使用了建造者模式,如XMLConfigBuilderXMLMapperBuilderMapperAnnotationBuilderCacheBuilder等等。

也可以关注我的公众号:程序之声
图片
关注公众号,领取更多资源

本文为博主原创文章,未经博主允许不得转载。

评论

发表评论