6.建造者模式

1.盖房项目实际需求

  • 需要建房子:这一过程为打桩、 砌墙、封顶
  • 房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是各自实现的细节不同

在这里插入图片描述
代码实现:

AbstractHouse:房子的抽象父类,指定建造房子的规范,以及建造房子的具体流程

/** 建造者模式 :传统方式
 * @author compass
 * @version 1.0
 * @date 2021-07-07 11:13
 */
public abstract class AbstractHouse {
    
    
    /**
     * 打地基
     */
   public abstract void buildBasic();

    /**
     * 砌墙
     */
    public abstract void buildWalls();

    /**
     * 封顶
     */
    public abstract void  roofed();

    public void build(){
    
    
        buildBasic();
        buildWalls();
        roofed();
    }
}

CommonHouse:普通房子,继承 AbstractHouse 类,实现了建造房子中各个步骤的具体细节

/**
 * @author compass
 * @version 1.0
 * @date 2021-07-07 11:16
 */
public class CommonHouse extends AbstractHouse {
    
    
    /**
     * 打地基
     */
    @Override
    public void buildBasic() {
    
    
        System.out.println("普通房顶打地基");
    }

    /**
     * 砌墙
     */
    @Override
    public  void buildWalls() {
    
    
        System.out.println("普通房顶打地基");
    }

    /**
     * 封顶
     */
    @Override
    public  void roofed() {
    
    
        System.out.println("普通房顶打封顶");
    }
}

HighBuilding:高楼大厦,继承 AbstractHouse 类,实现了建造房子中各个步骤的具体细节

/**
 * @author compass
 * @version 1.0
 * @date 2021-07-07 11:26
 */
public class HighHouse extends  AbstractHouse{
    
    
    /**
     * 打地基
     */
    @Override
    public void buildBasic() {
    
    
        System.out.println("高级房子打地基");
    }

    /**
     * 砌墙
     */
    @Override
    public void buildWalls() {
    
    
        System.out.println("高级房子砌墙");
    }

    /**
     * 封顶
     */
    @Override
    public void roofed() {
    
    
        System.out.println("高级房子封顶");
    }
}

传统方式优缺点分析

  • 优点是比较好理解,简单易操作。
  • 设计的程序结构,过于简单,没有设计缓存层对象,程序的扩展和维护不好,也就是说,这种设计方案,把产品(即:房子) 和创建产品的过程(即:建房子流程) 封装在一起,代码耦合性增强了。
  • 解决方案:将产品和产品建造过程解耦 --> 建造者模式

2.建造者模式基本介绍

  1. 建造者模式(Builder Pattern) 又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。
  2. 建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。
  3. 实际应用场景:建造房子、组装车辆

3.建造者模式的四个角色

  1. Product(产品角色): 一个具体的产品对象
  2. Builder(抽象建造者): 创建一个Product对象的抽象接口(或抽象类),抽象建造者主要负责规范建造的流程,不关心具体的建造细节
    3.ConcreteBuilder(具体建造者): 实现接口,构建和装配各个部件,具体建造者负责实现具体的建造细节
  3. Director(指挥者): 构建一个使用Builder接口的具体实现类的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程

建造者模式UML类图

  • Product(产品类):一个具体的产品
  • Builder(抽象建造者):Builder 中组合了一个 Product 实例
  • ConcreteBuilder(具体建造者):实现了 Builder 中的抽象方法
  • Director(指挥者):将 Builder 的具体实现类聚合到 Director 中,在 Director 中调用具体的 Builder 完成具体产品的制造

4.建造者模式解决盖房问题

案例需求

需要建房子:这一过程为打桩、 砌墙、封顶。不管是普通房子也好,别墅也好都需要经历这些过程, 下面我们使用建造者模式(Builder Pattern)来完成

在这里插入图片描述
代码实现

House:产品类


/** 建造者模式
 * @author compass
 * @version 1.0
 * @date 2021-07-07 15:17
 */
public class House {
    
    
    private String base;
    private String wall;
    private String roofed;

    public House(String base, String wall, String roofed) {
    
    
        this.base = base;
        this.wall = wall;
        this.roofed = roofed;
    }

    public House() {
    
    
    }

    public String getBase() {
    
    
        return base;
    }

    public void setBase(String base) {
    
    
        this.base = base;
    }

    public String getWall() {
    
    
        return wall;
    }

    public void setWall(String wall) {
    
    
        this.wall = wall;
    }

    public String getRoofed() {
    
    
        return roofed;
    }

    public void setRoofed(String roofed) {
    
    
        this.roofed = roofed;
    }

    @Override
    public String toString() {
    
    
        return "House{" +
                "base='" + base + '\'' +
                ", wall='" + wall + '\'' +
                ", roofed='" + roofed + '\'' +
                '}';
    }
}

HouseBuilder:抽象建造者,规定制造房子的规范,并提供 buildHouse() 方法返回制造好的房子(产品)

/**
 * @author compass
 * @version 1.0
 * @date 2021-07-07 15:18
 */
public abstract class HouseBuilder {
    
    

    private House house =new House();

    /**
     *  打地基
     */
   public  abstract void buildBasic ();

    /**
     *  砌墙
     */
   public abstract void buildWall();

    /**
     *  封顶
     */
  public abstract void roofed();

    /**
     *  将House 构建好之后就返回
     * @return
     */
   public House build(){
    
    
    return house;
   }



}

CommonHouse:具体建造者,负责建造普通房子,重写父类 HouseBuilder 中的抽象方法来指定普通房子的建造细节


/**
 * @author compass
 * @version 1.0
 * @date 2021-07-07 15:21
 */
public class CommonHouse extends HouseBuilder {
    
    

    /**
     * 打地基
     */
    @Override
    public void buildBasic() {
    
    
        System.out.println("普通房子打地基");
    }

    /**
     * 砌墙
     */
    @Override
    public void buildWall() {
    
    
        System.out.println("普通房子砌墙");
    }

    /**
     * 封顶
     */
    @Override
    public void roofed() {
    
    
        System.out.println("普通房子封顶");
    }
}

HighBuilding:具体建造者,负责建造高楼大厦,重写父类 HouseBuilder 中的抽象方法来指定高楼大厦的建造细节

/**
 * @author compass
 * @version 1.0
 * @date 2021-07-07 15:30
 */
public class HighBuilding extends HouseBuilder {
    
    
    /**
     * 打地基
     */
    @Override
    public void buildBasic() {
    
    
        System.out.println("高楼房子打地基");
    }

    /**
     * 砌墙
     */
    @Override
    public void buildWall() {
    
    
        System.out.println("高楼房子砌墙");
    }

    /**
     * 封顶
     */
    @Override
    public void roofed() {
    
    
        System.out.println("高楼房子封顶");
    }
}

Client:客户端,发出建造房子的命令

/**
 * @author compass
 * @version 1.0
 * @date 2021-07-07 15:18
 */
public class Client {
    
    

    public static void main(String[] args) {
    
    
        CommonHouse commonHouse = new CommonHouse();
        HouseDirector director = new HouseDirector(commonHouse);
        director.construct();

        HighBuilding building = new HighBuilding();
        HouseDirector director2 = new HouseDirector(building);
        director2.construct();

    }
}

HouseDirector:指挥者,指挥具体的 Builder 对象制造产品,可指定制造产品的流程

/** 动态的去指定制作流程
 * @author compass
 * @version 1.0
 * @date 2021-07-07 15:22
 */
public class HouseDirector {
    
    

    private HouseBuilder houseBuilder = null;

    public HouseDirector(HouseBuilder houseBuilder) {
    
    
        this.houseBuilder = houseBuilder;
    }

    public void setHouseBuilder(HouseBuilder houseBuilder) {
    
    
        this.houseBuilder = houseBuilder;
    }

    // 将构造房子交给指挥者
    public House construct() {
    
    

        houseBuilder.buildBasic();
        houseBuilder.buildWall();
        houseBuilder.roofed();
        return houseBuilder.build();
    }
}

在这里插入图片描述

总结

  1. Housebuilder是抽象建造者,提供需要实现的功能,并且组合了产品House

  2. CommonHouse和HighHouse继承自HouseBuilder,并且实现父类的方法

  3. HouseDirector中聚合了 Housebuilder ,也就是说只要是 Housebuilder的子类,他都可以进行指挥调用。

  4. Client只需要去调用HouseDirector(传入具体的建造者,让指挥者去调用建造者即可)

5.JDK StringBuilder

StringBuilder的 append() 方法:调用父类AbstractStringBuilder 的 append() 方法

AbstractStringBuilder的 append() 方法是由Appendable接口定义的规范

Appendable接口:定义了 append() 方法的规范,相当于是一个抽象的建造者

源码中建造者模式角色分析

  1. Appendable 接口定义了多个 append() 方法(抽象方法),即 Appendable 为抽象建造者,定义了制造产品的抽象方法(规范),抽象定义了 append方法能做的事情
public interface Appendable {
    
    


    Appendable append(CharSequence csq) throws IOException;

  
    Appendable append(CharSequence csq, int start, int end) throws IOException;

    Appendable append(char c) throws IOException;
}
  1. AbstractStringBuilder 实现了 Appendable 接口方法,这里的 AbstractStringBuilder 已经是建造者,只是不能实例化

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    
    
    /**
     * The value is used for character storage.
     */
    char[] value;

    /**
     * The count is the number of characters used.
     */
    int count;

    /**
     * This no-arg constructor is necessary for serialization of subclasses.
     */
    AbstractStringBuilder() {
    
    
    }

    /**
     * Creates an AbstractStringBuilder of the specified capacity.
     */
    AbstractStringBuilder(int capacity) {
    
    
        value = new char[capacity];
    }

    /**
     * Returns the length (character count).
     *
     * @return  the length of the sequence of characters currently
     *          represented by this object
     */
    @Override
    public int length() {
    
    
        return count;
    }

  

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

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

    // Documentation in subclasses because of synchro difference
    public AbstractStringBuilder append(StringBuffer sb) {
    
    
        if (sb == null)
            return appendNull();
        int len = sb.length();
        ensureCapacityInternal(count + len);
        sb.getChars(0, len, value, count);
        count += len;
        return this;
    }

    /**
     * @since 1.8
     */
    AbstractStringBuilder append(AbstractStringBuilder asb) {
    
    
        if (asb == null)
            return appendNull();
        int len = asb.length();
        ensureCapacityInternal(count + len);
        asb.getChars(0, len, value, count);
        count += len;
        return this;
    }

    // Documentation in subclasses because of synchro difference
    @Override
    public AbstractStringBuilder append(CharSequence s) {
    
    
        if (s == null)
            return appendNull();
        if (s instanceof String)
            return this.append((String)s);
        if (s instanceof AbstractStringBuilder)
            return this.append((AbstractStringBuilder)s);

        return this.append(s, 0, s.length());
    }

    private AbstractStringBuilder appendNull() {
    
    
        int c = count;
        ensureCapacityInternal(c + 4);
        final char[] value = this.value;
        value[c++] = 'n';
        value[c++] = 'u';
        value[c++] = 'l';
        value[c++] = 'l';
        count = c;
        return this;
    }

   
    public AbstractStringBuilder append(char[] str) {
    
    
        int len = str.length;
        ensureCapacityInternal(count + len);
        System.arraycopy(str, 0, value, count, len);
        count += len;
        return this;
    }

  
    public AbstractStringBuilder append(boolean b) {
    
    
        if (b) {
    
    
            ensureCapacityInternal(count + 4);
            value[count++] = 't';
            value[count++] = 'r';
            value[count++] = 'u';
            value[count++] = 'e';
        } else {
    
    
            ensureCapacityInternal(count + 5);
            value[count++] = 'f';
            value[count++] = 'a';
            value[count++] = 'l';
            value[count++] = 's';
            value[count++] = 'e';
        }
        return this;
    }

 
    @Override
    public AbstractStringBuilder append(char c) {
    
    
        ensureCapacityInternal(count + 1);
        value[count++] = c;
        return this;
    }

  
    public AbstractStringBuilder append(int i) {
    
    
        if (i == Integer.MIN_VALUE) {
    
    
            append("-2147483648");
            return this;
        }
        int appendedLength = (i < 0) ? Integer.stringSize(-i) + 1
                                     : Integer.stringSize(i);
        int spaceNeeded = count + appendedLength;
        ensureCapacityInternal(spaceNeeded);
        Integer.getChars(i, spaceNeeded, value);
        count = spaceNeeded;
        return this;
    }

   
    public AbstractStringBuilder append(long l) {
    
    
        if (l == Long.MIN_VALUE) {
    
    
            append("-9223372036854775808");
            return this;
        }
        int appendedLength = (l < 0) ? Long.stringSize(-l) + 1
                                     : Long.stringSize(l);
        int spaceNeeded = count + appendedLength;
        ensureCapacityInternal(spaceNeeded);
        Long.getChars(l, spaceNeeded, value);
        count = spaceNeeded;
        return this;
    }


    public AbstractStringBuilder append(float f) {
    
    
        FloatingDecimal.appendTo(f,this);
        return this;
    }

 
    public AbstractStringBuilder append(double d) {
    
    
        FloatingDecimal.appendTo(d,this);
        return this;
    }

  

 

}

  1. StringBuilder 既充当了指挥者角色,同时充当了具体的建造者, 因为建造方法的实现是由 AbstractStringBuilder 完成,而 StringBuilder 继承了AbstractStringBuilder
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
    
    

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

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

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

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


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

    @Override
    public StringBuilder append(char[] str) {
    
    
        super.append(str);
        return this;
    }

  

}
  • 建造者模式的注意事项和细节
  1. 客户端(使用程序)不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象
  2. 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同的产品对象
  3. 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程
    增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合 “开闭原则”
  4. 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制
    如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大, 因此在这种情况下,要考虑是否选择建造者模式

抽象工厂模式 和 建造者模式的区别

  1. 抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可
  2. 而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品,可以这样理解:建造者模式制造产品需要有一个具体的流程,对于不同产品整体流程相差不大,但是每个流程的实现细节较大

猜你喜欢

转载自blog.csdn.net/m0_46188681/article/details/118542678