建造者模式和StringBuilder源码解析

发布于 2020-10-13  402 次阅读


       在设计模式中建造者模式是一种创建型模式

创建者模式:将复杂的生产过程与产品表现本身进行分离,使同样的生产过程产生不同的产品,对两者进行解耦

创建者模式分为四个角色:

Builder(抽象建造者):它为创建一个产品Product对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类方法是buildPartX(),它们用于创建复杂对象的各个部件;另一类方法是getResult(),它们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。

ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确它所创建的复杂对象,也可以提供一个方法返回创建好的复杂产品对象。

Product(产品角色):它是被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。

Director(指挥者):指挥者又称为导演类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,可以在其construct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象(也可以通过配置文件和反射机制),然后通过指挥者类的构造函数或者Setter方法将该对象传入指挥者类中。

例:我们以电脑的创建为例

通俗的讲:

产品类:电脑生产需要的零件

抽象建造者:电脑零件设计图中和产品交付书

具体建造者:按图设计零件

指挥者:依照零件组装电脑

总体UML图:

产品角色:

 //品牌
private String Brand;
//CPU
private String CPU;
//主板
private String Mainboard;
//显卡
private String Graphics;

public String getBrand() {
return Brand;
}
public void setBrand(String brand) {
Brand = brand;
}
public String getCPU() {
return CPU;
}
public void setCPU(String cPU) {
CPU = cPU;
}
public String getMainboard() {
return Mainboard;
}
public void setMainboard(String mainboard) {
Mainboard = mainboard;
}
public String getGraphics() {
return Graphics;
}
public void setGraphics(String graphics) {
Graphics = graphics;
}
@Override
public String toString() {
return "computerproduct [Brand=" + Brand + ", CPU=" + CPU + ", Mainboard=" + Mainboard + ", Graphics="
+ Graphics + "]";
}

 

抽象建造者:

 //组合一个产品对象
computerproduct computer=new computerproduct();

//创建品牌
public abstract void builderBrand();
//创建CPU
public abstract void builderCPU();
//创建显卡
public abstract void builderGraohics();
//创建主板
public abstract void builderMainboard();


public computerproduct getcomputers() {

//返回具体对象
return computer;
}

 

具体建造者(这里写了两个建造者):

建造者1:

//创建一个机械师电脑
@Override
public void builderBrand() {
// TODO Auto-generated method stub
computer.setBrand("机械师(深海幽灵)");
}

@Override
public void builderCPU() {
// TODO Auto-generated method stub
computer.setCPU("intel i7");
}

@Override
public void builderGraohics() {
// TODO Auto-generated method stub
computer.setGraphics("GTX2070 独立8GB");
}

@Override
public void builderMainboard() {
// TODO Auto-generated method stub
computer.setMainboard("深海主板");
}

建造者2:

//华硕,飞行堡垒
@Override
public void builderBrand() {
// TODO Auto-generated method stub
computer.setBrand("华硕(飞行堡垒)");
}

@Override
public void builderCPU() {
// TODO Auto-generated method stub
computer.setCPU("intel i7");
}

@Override
public void builderGraohics() {
// TODO Auto-generated method stub
computer.setGraphics("GTX2070 独立8GB");
}

@Override
public void builderMainboard() {
// TODO Auto-generated method stub
computer.setMainboard("华硕主板");
}

 

指挥者:

 abstractbuildercomputer computer;

public Directorcomputer(abstractbuildercomputer computer) {
this.computer=computer;
}

public computerproduct getcomputer1() {
computer.builderBrand();
computer.builderCPU();
computer.builderGraohics();
computer.builderMainboard();
return computer.getcomputers();
}

 

测试类:

public static void main(String[] args) {

concretenessbuildercomputer2 a=new concretenessbuildercomputer2();

Directorcomputer my=new Directorcomputer(a);

System.out.print(my.getcomputer1().toString());
}

输出结果:

computerproduct [Brand=华硕(飞行堡垒), CPU=intel i7, Mainboard=华硕主板, Graphics=GTX2070 独立8GB]

建造者模式的主要优点

  • 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
  • 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。由于指挥者类针对抽象建造者编程,增加新的具体建造者无须修改原有类库的代码,系统扩展方便,符合 "开闭原则"。
  • 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

建造者模式的主要缺点

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

 

一,StringBuilder源码解析

StringBuilder是创建者模式的一个典型案例,但它根标准的建造者模式也出入

stringbuilder继承的类和实现的接口:

这里我们只看AbstractStringBuilder类结构

AbstractStringBuilder继承了Appendable, CharSequence,因为CharSequence是char值的可读序列不做为建造者我们忽略

Appendable源码:

public interface Appendable {
    Appendable append(CharSequence var1) throws IOException;

    Appendable append(CharSequence var1, int var2, int var3) throws IOException;

    Appendable append(char var1) throws IOException;
}

它定义了append规则

AbstractStringBuilder源码一部分:

public AbstractStringBuilder append(Object obj) {
    return this.append(String.valueOf(obj));
}

public AbstractStringBuilder append(String str) {
    if (str == null) {
        return this.appendNull();
    } else {
        int len = str.length();
        this.ensureCapacityInternal(this.count + len);
        this.putStringAt(this.count, str);
        this.count += len;
        return this;
    }
}

public AbstractStringBuilder append(StringBuffer sb) {
    return this.append((AbstractStringBuilder)sb);
}

它实现了Appendable的append方法

StringBuilder源码:

public StringBuilder append(Object obj) {
    return this.append(String.valueOf(obj));
}

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

public StringBuilder append(StringBuffer sb) {
    super.append(sb);
    return this;
}

public StringBuilder append(CharSequence s) {
    super.append(s);
    return this;
}

public StringBuilder append(CharSequence s, int start, int end) {
    super.append(s, start, end);
    return this;
}

基本上所有方法都通过super()调用了父类,并返回了自己本身

在StringBuilder中,Appendable做为抽象创建者,AbstractStringBuilder属于具体创建者,StringBuilder即是产品类也是指挥者

 

二,StringBuffer源码

StringBuffer的继承类

它和StringBuilder一样都是继承AbstractStringBuilder类,实现接口也是一样的

但看它的一部分源码:

public synchronized int compareTo(StringBuffer another) {
    return super.compareTo(another);
}

public synchronized int length() {
    return this.count;
}

public synchronized int capacity() {
    return super.capacity();
}

public synchronized void ensureCapacity(int minimumCapacity) {
    super.ensureCapacity(minimumCapacity);
}

public synchronized void trimToSize() {
    super.trimToSize();
}

public synchronized void setLength(int newLength) {
    this.toStringCache = null;
    super.setLength(newLength);

前面都加了synchronized关键字,以此得知它和StringBuilder相比它是线程安全的,而StringBuilder是非线程安全的(其他功能一致)


路漫漫其修远兮,吾将上下而求索