建造者模式及在源码中的实践
建造者模式
用多个简单的对象创建一个复杂的对象,将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式在设计时有四种角色:
1.Builder:复杂产品对象的抽象接口
2.ConcreteBuilder:Builder的实现类,主要定义装配流程
3.Director:构造一个使用Builder抽象接口的对象
4.Product:表示被构造的复杂对象。ConcreteBuilder定义了该复杂对象的装配流程,而Product定义了该复杂对象的结构和内部表示。
建造者抽象类
public abstract class Builder {
public abstract void buildCPU(String cpu);
public abstract void buildMainBoard(String mainBoard);
public abstract void buildHardDisk(String hardDisk);
public abstract void buildDisplayCard(String displayCard);
public abstract void buildPower(String power);
public abstract void buildMemory(String memory);
public abstract Computer createComputer();
}
具体建造者类
public class ActualBuilder extends Builder {
private Computer computer = new Computer();
@Override
public void buildCPU(String cpu) {
computer.setCpu(cpu);
}
@Override
public void buildMainBoard(String mainBoard) {
computer.setMainBoard(mainBoard);
}
@Override
public void buildHardDisk(String hardDisk) {
computer.setHardDisk(hardDisk);
}
@Override
public void buildDisplayCard(String displayCard) {
computer.setDisplayCard(displayCard);
}
@Override
public void buildPower(String power) {
computer.setPower(power);
}
@Override
public void buildMemory(String memory) {
computer.setMemory(memory);
}
@Override
public Computer createComputer() {
return computer;
}
}
复杂对象
public class Computer {
private String cpu;
private String mainBoard;
private String hardDisk;
private String displayCard;
private String power;
private String memory;
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public String getMainBoard() {
return mainBoard;
}
public void setMainBoard(String mainBoard) {
this.mainBoard = mainBoard;
}
public String getHardDisk() {
return hardDisk;
}
public void setHardDisk(String hardDisk) {
this.hardDisk = hardDisk;
}
public String getDisplayCard() {
return displayCard;
}
public void setDisplayCard(String displayCard) {
this.displayCard = displayCard;
}
public String getPower() {
return power;
}
public void setPower(String power) {
this.power = power;
}
public String getMemory() {
return memory;
}
public void setMemory(String memory) {
this.memory = memory;
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", mainBoard='" + mainBoard + '\'' +
", hardDisk='" + hardDisk + '\'' +
", displayCard='" + displayCard + '\'' +
", power='" + power + '\'' +
", memory='" + memory + '\'' +
'}';
}
}
Director类
public class DirectorBoss {
private Builder builder;
public void setBuilder(Builder builder) {
this.builder = builder;
}
public Computer createComputer(String cpu,String mainBoard,
String hardDisk,String displayCard,
String power,String memory){
this.builder.buildCPU(cpu);
this.builder.buildMainBoard(mainBoard);
this.builder.buildHardDisk(hardDisk);
this.builder.buildDisplayCard(displayCard);
this.builder.buildPower(power);
this.builder.buildMemory(memory);
return this.builder.createComputer();
}
}
测试
public class Test {
public static void main(String[] args) {
Builder builder = new ActualBuilder();
DirectorBoss directorBoss = new DirectorBoss();
directorBoss.setBuilder(builder);
Computer computer = directorBoss.createComputer("酷睿I7","华硕主板","希捷2T硬盘","英伟达显卡","长城电源","威刚内存条8G");
System.out.println(computer);
}
}
输出
对于组装电脑,是先装cpu,还是先装硬盘,只需要调整DirectorBoss类的执行顺序即可
当然,也可以用这种链式调用
public class Test {
public static void main(String[] args) {
Computer computer = new Computer.ComputerBuilder().buildCPU("酷睿I7").buildMainBoard("华硕主板").build();
System.out.println(computer);
}
}
在Computer类里面增加内部ComputerBuilder类并实现构造函数即可,这样调用顺序就可以控制在应用层
public class Computer {
private String cpu;
private String mainBoard;
private String hardDisk;
private String displayCard;
private String power;
private String memory;
public Computer(ComputerBuilder computerBuilder){
this.cpu = computerBuilder.cpu;
this.mainBoard = computerBuilder.mainBoard;
this.hardDisk = computerBuilder.hardDisk;
this.displayCard = computerBuilder.displayCard;
this.power = computerBuilder.power;
this.memory = computerBuilder.memory;
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", mainBoard='" + mainBoard + '\'' +
", hardDisk='" + hardDisk + '\'' +
", displayCard='" + displayCard + '\'' +
", power='" + power + '\'' +
", memory='" + memory + '\'' +
'}';
}
public static class ComputerBuilder{
private String cpu;
private String mainBoard;
private String hardDisk;
private String displayCard;
private String power;
private String memory;
public ComputerBuilder buildCPU(String cpu){
this.cpu = cpu;
return this;
}
public ComputerBuilder buildMainBoard(String mainBoard){
this.mainBoard = mainBoard;
return this;
}
public ComputerBuilder buildHardDisk(String hardDisk){
this.hardDisk = hardDisk;
return this;
}
public ComputerBuilder buildDisplayCard(String displayCard){
this.displayCard = displayCard;
return this;
}
public ComputerBuilder buildPower(String power){
this.power = power;
return this;
}
public ComputerBuilder buildMemory(String memory){
this.memory = memory;
return this;
}
public Computer build(){
return new Computer(this);
}
}
}
输出
现在来看在源码中的应用:
在StringBuilder中,可以看到其也是使用了建造者模式
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
再看看BeanDefinitionBuilder类
来到setFactoryMethod方法,我们写的第二种与其类似,就是典型的建造者模式
MyBatis中的SqlSessionFactoryBuilder类,也是用了建造者模式,返回SqlSessionFactory对象
看其中一个build方法
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
parser.parse()调用了哪个函数,可以看到来到了XMLConfigBuilder类里面,看类名不难猜出又用了建造者模式
可以看到在parseConfiguration方法的参数就是一个根节点,内部就是各个组件的装配流程
至此可以知道XMLConfigBuilder创建复杂对象的Configuration,而SqlSessionFactoryBuilder只不过是对XMLConfigBuilder做了一层简单的封装,用建造者来包装一层建造者
再来看看SqlSessionManager类,可以明显看出多个newInnetstance重载函数的就调用了SqlSessionFactoryBuilder建造者来创建复杂对象
public class SqlSessionManager implements SqlSessionFactory, SqlSession {
private final SqlSessionFactory sqlSessionFactory;
private final SqlSession sqlSessionProxy;
private ThreadLocal<SqlSession> localSqlSession = new ThreadLocal<SqlSession>();
private SqlSessionManager(SqlSessionFactory sqlSessionFactory) {
this.sqlSessionFactory = sqlSessionFactory;
this.sqlSessionProxy = (SqlSession) Proxy.newProxyInstance(
SqlSessionFactory.class.getClassLoader(),
new Class[]{SqlSession.class},
new SqlSessionInterceptor());
}
public static SqlSessionManager newInnetstance(Reader reader) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, null));
}
public static SqlSessionManager newInstance(Reader reader, String environment) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, environment, null));
}
public static SqlSessionManager newInstance(Reader reader, Properties properties) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(reader, null, properties));
}
public static SqlSessionManager newInstance(InputStream inputStream) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, null, null));
}
public static SqlSessionManager newInstance(InputStream inputStream, String environment) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, environment, null));
}
public static SqlSessionManager newInstance(InputStream inputStream, Properties properties) {
return new SqlSessionManager(new SqlSessionFactoryBuilder().build(inputStream, null, properties));
}
public static SqlSessionManager newInstance(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionManager(sqlSessionFactory);
}
...
}
参考:
https://zhuanlan.zhihu.com/p/58093669
http://www.imooc.com/t/2705746