设计模式-----Builder模式
前言
近日,看到Myabtis中组件中SqlSessionFactory由SqlSessionFactoryBuilder().build()生成时,且采用Builder模式,遂记录学习之。
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
1、什么是Builder模式?
(1)对于复杂的对象,如果只是用构造方法创建的话,构造方法中会存在很多的逻辑,那么我们可以一步步有秩序构建它,从而降低复杂度;
(2)对于复杂的对象,使用者不必知道其内部是如何实现的清下,逐步构造需要的实例对象;
2、什么情况下使用Builder模式?
(1)将一个复杂对象的构建与它的表示分离,即相同的构造过程可以有不同表示;
(2)当有多个构造器且需要传入不同的参数表示不同的产品时(即可以弥补工厂模式等无法选择多参数的缺点)
(3)传入参数情况比较灵活且复杂的情况,或者说一开始不需要明确参数的情况。
(4)框架中很多Configuration配置都会用到Builder模式。
3、具体使用Builder例子
(1)以前经常通过不同构造器传入不同的参数构造不同复杂的对象,比如我们现在需要一个User的不同情况对象
- 只有id和name
- 有id、name、age
- 有id、name、age、address
public class User { private int id; private String name; private int age; private String address; //不同的构造器传入不同的参数,创造不同的复杂的产品 public User(int id, String name) { this.id = id; this.name = name; } public User(int id, String name, int age) { this.id = id; this.name = name; this.age = age; } public User(int id, String name, int age, String address) { this.id = id; this.name = name; this.age= age; this.address = address; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
测试类这样编写:
public class Main { public static void main(String[] args) { //情况1:id、姓名 User user = new User(1, "Zhangsan"); //情况2:id、姓名、年龄 User user2 = new User(2,"Lisi",22); //情况3:id、姓名、年龄、地址 User user3 = new User(3,"Wangwu",23,"Beijing"); //情况4:id与年龄不清楚,很容易混淆,必须得查看源码或者文档才能知道哪个参数位置id/年龄 User user4 = new User(24,"Wangwu",24,"Beijing"); } }
OK,这样是没有问题的,但是会有以下弊端:
- 就好比情况4。当传入的参数很多并且没有说明文档的情况下,之后阅读完源码后才能更好地使用。那么就有可能对源码进行修改,这样就违背了在应用中一个好的设计模块的原则,即设计模式中的开闭原则(Open-Closed Principle, OCP,对修改封闭)
- 每种情况都得编写一个的构造器,没有一点的灵活度。再比如这里address属性是可选的,可以不传入,那么灵活度同样很低!
(2)接下来就使用Builder模式创建,注意:Builder主要采用Java静态内部类
/** * 利用Builer模式灵活面对复杂对象的创建 * @author Lijian * */ public class User2 { private int id; private String name; private int age; private String address; private User2(Builder builder) { this.id = builder.id; this.name = builder.name; this.age = builder.age; this.address = builder.address; } static class Builder{ private int id; private String name; private int age; private String address; //灵活选择参数 public Builder setId(int id) { this.id = id; return this; } public Builder setName(String name) { this.name = name; return this; } public Builder setAddress(String address) { this.address = address; return this; } public Builder setAge(int age) { this.age = age; return this; } //最后build返回User2对象 public User2 build() { return new User2(this); } } }
测试类:
public class Main { public static void main(String[] args) { //通过build创建了User2对象,之后通过setXXX方法可灵活初始化属性,最后build返回对象 User2 user = new User2.Builder().setId(1).setName("Lijian").setAge(22).build(); //情况1:id、姓名 User2 user2 = new User2.Builder().setId(2).setName("Zhangsan").build(); //情况2:id、姓名、年轻、地址 User2 user3 = new User2.Builder().setId(2).setName("Lisi").build(); //情况3:id与age很明显能区分 User2 user4 = new User2.Builder().setId(23).setAge(23).build(); } }
通过setXXX()方法灵活选择参数,最后build()方法“闭合”返回对象。很适用于复杂对象的创建,此处让我想起Java8新特性中的Stream API(https://blog.csdn.net/mynewclass/article/details/80393308)的一个特点:懒加载。是的,有点“懒加载”的味道,不需要立马指定属性,也不会立马生效,之后最后的操作build()才会生效!