Java23种设计模式之建造者模式的学习(通俗易懂)

源码链接(Gitee码云):https://gitee.com/oldou/javadesignpatterns
这里有我整理好的Java23种设计模式的源码以及博客教程,博客教程中介绍了Java23种设计的模式的各种实现方式以及应用场景,非常适用于学习以及提高我们的设计思维,如果对大家有所帮助,请记得star一下给予作者一定的精神支持,你的star是我写出更好的博客的动力,谢谢大家。

建造者模式(Builder pattern)

  • 建造者模式也属于创建型模式,它提供了一种创建对象的最佳方式。

  • 定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示

  • 主要作用:在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。

建造者的应用场景

  • 需要生成的产品对象有复杂的内部结构,这些产品对象具备共性;
  • 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
  • 适合于一个具有较多的零件(属性)的产品(对象)的创建过程。
  • 当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式

开发中应用场景:

  • StringBuilder类的append方法
  • SQL中的PreparedStatement
  • JDOM中,DomBuilder、SAXBuilder

传统的建造者模式

Java23种设计模式之建造者模式的学习(通俗易懂)_第1张图片
如上图所示,建造者模式的四个角色。

  • Product::最终要生成的对象,例如 Computer实例。
  • Builder: 构建者的抽象基类(有时会使用接口代替)。其定义了构建 Product的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法Product getProduct()。
  • 具体的Builder: Builder的实现类。
  • Director:决定如何构建最终产品的算法,其会包含一个负责组装的方法void Construct(Builder builder), 在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的 getProduct() 方法获得最终的产品。

例子:假如我们现在有一个计算机类Computer,其中cpu和ram是必选的参数,其他的三个是可选的参数,那么我们如何来构建这个类的实例呢?下面我们通过传统的建造者模式来实现一下:

传统的建造者模式

第一步:创建我们的目标Computer类:

package com.oldou.builder.demo03;

/**
 * 产品:相当于就是Product
 */
public class Computer {
     
    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选
    private String keyboard;//可选
    private String display;//可选

    public Computer(String cpu, String ram){
     
        this.cpu = cpu;
        this.ram = ram;
    }

    public void setUsbCount(int usbCount) {
     
        this.usbCount = usbCount;
    }

    public void setKeyboard(String keyboard) {
     
        this.keyboard = keyboard;
    }

    public void setDisplay(String display) {
     
        this.display = display;
    }

    @Override
    public String toString() {
     
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", ram='" + ram + '\'' +
                ", usbCount=" + usbCount +
                ", keyboard='" + keyboard + '\'' +
                ", display='" + display + '\'' +
                '}';
    }
}

第二步:创建抽象构建者类

/**
 * 抽象的建造者Builder
 */
public abstract class ComputerBuilder {
     
    public abstract void setUsbCount();
    public abstract void setKeyboard();
    public abstract void setDisplay();

    public abstract Computer getComputer();
}

第三步:实体构建者类,我们可以根据要构建的产品种类产生多了实体构建者类,这里我们需要构建两种品牌的电脑,苹果电脑和联想电脑,所以我们生成了两个实体构建者类。

苹果电脑建造者类:

/**
 * 苹果电脑的建造者
 */
public class MacComputerBuilder extends ComputerBuilder {
     
    private Computer computer;
    public MacComputerBuilder(String cpu,String ram){
     
        computer = new Computer(cpu,ram);
    }

    @Override
    public void setUsbCount() {
     
        computer.setUsbCount(2);
    }

    @Override
    public void setKeyboard() {
     
        computer.setKeyboard("苹果键盘");
    }

    @Override
    public void setDisplay() {
     
        computer.setDisplay("苹果显示器");
    }

    @Override
    public Computer getComputer() {
     
        return computer;
    }
}

联想电脑建造者类

package com.oldou.builder.demo03;

/**
 * 联想电脑的建造者
 */
public class LenovoComputerBuilder extends ComputerBuilder {
     
    private Computer computer;
    public LenovoComputerBuilder(String cpu, String ram){
     
        computer = new Computer(cpu,ram);
    }

    @Override
    public void setUsbCount() {
     
        computer.setUsbCount(4);
    }

    @Override
    public void setKeyboard() {
     
        computer.setKeyboard("联想键盘");
    }

    @Override
    public void setDisplay() {
     
        computer.setDisplay("联想显示器");
    }

    @Override
    public Computer getComputer() {
     
        return computer;
    }
}

第四步:指导者类(Director):指挥电脑建造者按照以下方式建造电脑

package com.oldou.builder.demo03;

/**
 * 指导者类:Director
 * 负责指挥构建哪种电脑
 */
public class Director {
     
	//指挥电脑建造者按照以下建造电脑,下面的属性可选
    public void makeComputer(ComputerBuilder builder){
     
        builder.setUsbCount();
        builder.setDisplay();
        builder.setKeyboard();
    }
}

测试
首先生成一个director (1),然后生成一个目标builder (2),接着使用director组装builder (3),组装完毕后使用builder创建产品实例 (4)。

public class Client {
     
    public static void main(String[] args) {
     
        //创建指挥者 首先生成一个director
        Director director = new Director(); //1
        //然后生成一个目标builder
        ComputerBuilder builder = new MacComputerBuilder("I7处理器", "三星123");//2

        //接着使用director组装builder
        director.makeComputer(builder);//3

        //组装完毕后使用builder创建产品实例
        Computer computer = builder.getComputer();//4
        System.out.println("苹果电脑"+computer.toString());
		
		//建造联想电脑
        ComputerBuilder lenovoBuilder = new LenovoComputerBuilder("I9处理器", "海力士333");
        director.makeComputer(lenovoBuilder);
        Computer lenovoComputer = lenovoBuilder.getComputer();
        System.out.println("联想电脑:"+lenovoComputer.toString());
    }
}

输出:
在这里插入图片描述

使用静态内部类的方式实现建造者

静态内部类的方式是传统builder模式的变种, 其中省略了director 这个角色,将构建算法交给了client端,其次将builder 写到了要构建的产品类里面,最后采用了链式调用。

如何实现呢?

  • 1、在Computer 中创建一个静态内部类 Builder,然后将Computer 中的参数都复制到Builder类中;
  • 2、在Computer中创建一个private的构造函数,参数为Builder类型;
  • 3、在Builder中创建一个public的构造函数,参数为Computer中必填的那些参数,cpu 和ram;
  • 4、在Builder中创建设置函数,对Computer中那些可选参数进行赋值,返回值为Builder类型的实例;
  • 5、在Builder中创建一个build()方法,在其中构建Computer的实例并返回。

以下就是代码的实现:

package com.oldou.builder.demo04;

/**
 * 产品:电脑
 */
public class Computer {
     
    private final String cpu;//必须
    private final String ram;//必须
    private final int usbCount;//可选
    private final String keyboard;//可选
    private final String display;//可选

    private Computer(Builder builder){
     
        this.cpu=builder.cpu;
        this.ram=builder.ram;
        this.usbCount=builder.usbCount;
        this.keyboard=builder.keyboard;
        this.display=builder.display;
    }
    //静态内部类的方式建造电脑
    public static class Builder{
     
        private String cpu;//必须
        private String ram;//必须
        private int usbCount;//可选
        private String keyboard;//可选
        private String display;//可选

        public Builder(String cup,String ram){
     
            this.cpu=cup;
            this.ram=ram;
        }

        public Builder setUsbCount(int usbCount) {
     
            this.usbCount = usbCount;
            return this;
        }
        public Builder setKeyboard(String keyboard) {
     
            this.keyboard = keyboard;
            return this;
        }
        public Builder setDisplay(String display) {
     
            this.display = display;
            return this;
        }

        //构建Computer的实例并返回
        public Computer build(){
     
            return new Computer(this);
        }
    }
}

使用方式:在客户端使用链式调用,一步一步的把对象构建出来。

Computer computer=new Computer.Builder("因特尔","三星")
                .setDisplay("三星24寸")
                .setKeyboard("罗技")
                .setUsbCount(2)
                .build();

总结:通过静态内部类方式实现零件无序装配构造,这种方式使用更加灵活,更符合定义。内部有复杂对象的默认实现,使用时可以根据用户需求自由定义更改内容,并且无需改变具体的构造方式。就可以生产出不同复杂产品。

建造者模式的优缺点

优点

  • 将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰;
  • 产品的建造和表示分离,实现了解耦。使用建造者模式可以使客户端不必知道产品内部组成的细节;
  • 具体的建造者类之间是相互独立的,这有利于系统的扩展。增加新的具体建造者无需修改原有类库的代码,符合“开闭原则“。

缺点

  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

建造者与抽象工厂的比较

  • 与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族。

  • 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象。

  • 如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车!

本文建造者模式的代码示例部分来自知乎的作者:shusheng007 ,
原文链接:https://zhuanlan.zhihu.com/p/58093669

在学习建造者模式的时候,很多视频讲得有点难理解,所以就去看了很多文章,其中觉得这个作者的文章写得真的不错,讲得也很明白,在其基础上我自己稍作了一些总结。

你可能感兴趣的:(设计模式,学习笔记,设计模式)