设计模式篇(Java):建造者模式

设计模式篇(Java):原型模式

七、建造者模式

需求示例

需要建一栋房子,步骤:打地基 -> 砌墙 -> 封顶 (不管是别墅还是小破楼都是这一流程)
现在需要创建不同的房子:别墅、小破楼等等
传统的解决方案

在这里插入图片描述

代码示例:

抽象实现过程

/**
 * @author cVzhanshi
 * @create 2023-06-20 16:58
 */
public abstract class AbstractHouse {
    
    

    // 建房子步骤一
    public abstract void buildOne();

    // 建房子步骤二
    public abstract void buildTwo();

    // 建房子步骤三
    public abstract void buildThree();
    
    // 建房子
    public void build() {
    
    
        buildOne();
        buildTwo();
        buildThree();
    }
}

具体实现过程子类

/**
 * @author cVzhanshi
 * @create 2023-06-20 17:00
 */

// 小房子
@Slf4j
public class SmallHouse extends AbstractHouse {
    
    
    @Override
    public void buildOne() {
    
    
        log.info("建小房子第一步:buildOne");
    }

    @Override
    public void buildTwo() {
    
    
        log.info("建小房子第二步:buildTwo");
    }

    @Override
    public void buildThree() {
    
    
        log.info("建小房子第三步:buildThree");
    }
}

// 大房子
@Slf4j
public class BigHouse extends AbstractHouse{
    
    
    @Override
    public void buildOne() {
    
    
        log.info("建大房子第一步:buildOne");
    }

    @Override
    public void buildTwo() {
    
    
        log.info("建大房子第二步:buildTwo");
    }

    @Override
    public void buildThree() {
    
    
        log.info("建大房子第三步:buildThree");
    }
}

客户端建房子

@Slf4j
public class Client {
    public static void main(String[] args) {
        // 建大房子
        BigHouse bigHouse = new BigHouse();
        bigHouse.build();
        log.info("=-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=");
        // 建小房子
        SmallHouse smallHouse = new SmallHouse();
        smallHouse.build();
    }
}

// 输出
17:15:44.332 [main] INFO cn.cvzhanshi.design.builder.BigHouse - 建大房子第一步:buildOne
17:15:44.336 [main] INFO cn.cvzhanshi.design.builder.BigHouse - 建大房子第二步:buildTwo
17:15:44.336 [main] INFO cn.cvzhanshi.design.builder.BigHouse - 建大房子第三步:buildThree
17:15:44.336 [main] INFO cn.cvzhanshi.design.builder.Client - =-=-=-=-=-=-=-=--=-=-=-=-=-=-=-=
17:15:44.338 [main] INFO cn.cvzhanshi.design.builder.SmallHouse - 建小房子第一步:buildOne
17:15:44.338 [main] INFO cn.cvzhanshi.design.builder.SmallHouse - 建小房子第二步:buildTwo
17:15:44.338 [main] INFO cn.cvzhanshi.design.builder.SmallHouse - 建小房子第三步:buildThree

达到了new不同类实现不同的房子

分析:

  • 优点:比较好理解,清晰明了;
  • 缺点:设计的程序结构,过于简单,没有设计缓存层对象,程序的扩展和维护不好。把产品和创建产品的过程封装在了一起,耦合性增强了。
  • 解决方案:将产品和产品的创建过程解耦 => 建造者模式

7.1 建造者模式基本介绍

  • 它可以把复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同属性的对象

  • 建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。

四个角色

  • Product(产品角色):一个具体的产品对象。
  • Builder(抽象建造者):创建一个Product对象的各个属性的指定接口或抽象类
  • ConcreteBuilder(具体建造者):实现接口或者继承抽象类,构建产品的各个属性。
  • Director(指挥者):构建一个使用Builder接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程。

对应的原理类图:

在这里插入图片描述

7.2 建造者模式实现需求示例

思路分析类图

在这里插入图片描述

根据类图编写代码

产品类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class House {
    
    
    private String one;
    
    private String two;
    
    private String three;
}

抽象的建造者

/**
 * @author cVzhanshi
 * @create 2023-06-20 18:20
 */
public abstract class HouseBuilder {
    
    
    protected House house = new House();

    // 建房子步骤一
    public abstract void buildOne();

    // 建房子步骤二
    public abstract void buildTwo();

    // 建房子步骤三
    public abstract void buildThree();
    
    public House buildHouse() {
    
    
        return house;
    }
}

具体实现的建造者

@Slf4j
public class LowHouseBuilder extends HouseBuilder {
    
    
    @Override
    public void buildOne() {
    
    
        log.info("小破楼:One");
    }

    @Override
    public void buildTwo() {
    
    
        log.info("小破楼:Two");
    }

    @Override
    public void buildThree() {
    
    
        log.info("小破楼:Three");
    }
}

@Slf4j
public class HighHouseBuilder extends HouseBuilder{
    
    
    @Override
    public void buildOne() {
    
    
        log.info("建高楼咯:One");
    }

    @Override
    public void buildTwo() {
    
    
        log.info("建高楼咯:Two");
    }

    @Override
    public void buildThree() {
    
    
        log.info("建高楼咯:Three");
    }
}

指挥者

@Data
@AllArgsConstructor
public class HouseDirector {
    
    
    private HouseBuilder houseBuilder;
    
    
    public House constructHouse() {
    
    
        houseBuilder.buildOne();
        houseBuilder.buildTwo();
        houseBuilder.buildThree();
        return houseBuilder.buildHouse();
    }
    
}

客户端使用

@Slf4j
public class Client {
    
    
    public static void main(String[] args) {
    
    
        // 盖小破楼
        HouseBuilder lowHouseBuilder = new LowHouseBuilder();
        // 准备创建房子的指挥者
        HouseDirector houseDirector = new HouseDirector(lowHouseBuilder);

        // 完成盖房子,返回产品
        House house = houseDirector.constructHouse();

        log.info("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-");

        // 盖高楼
        HouseBuilder highHouseBuilder = new HighHouseBuilder();
        // 准备创建房子的指挥者
        HouseDirector houseDirector2 = new HouseDirector(highHouseBuilder);

        // 完成盖房子,返回产品
        House house2 = houseDirector2.constructHouse();


    }
}


// 输出
18:37:39.160 [main] INFO cn.cvzhanshi.design.builder.LowHouseBuilder - 小破楼:One
18:37:39.164 [main] INFO cn.cvzhanshi.design.builder.LowHouseBuilder - 小破楼:Two
18:37:39.164 [main] INFO cn.cvzhanshi.design.builder.LowHouseBuilder - 小破楼:Three
18:37:39.164 [main] INFO cn.cvzhanshi.design.builder.Client - -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
18:37:39.164 [main] INFO cn.cvzhanshi.design.builder.HighHouseBuilder - 建高楼咯:One
18:37:39.164 [main] INFO cn.cvzhanshi.design.builder.HighHouseBuilder - 建高楼咯:Two
18:37:39.164 [main] INFO cn.cvzhanshi.design.builder.HighHouseBuilder - 建高楼咯:Three

7.3 建造者模式在JDK源码中的使用

StringBuilder中的建造者模式

Appendable

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;
}

AbstractStringBuilder已经把Appendable的抽象方法都实现了

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    
    
	@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());
    }
    
    @Override
    public AbstractStringBuilder append(CharSequence s, int start, int end) {
    
    
        if (s == null)
            s = "null";
        if ((start < 0) || (start > end) || (end > s.length()))
            throw new IndexOutOfBoundsException(
                "start " + start + ", end " + end + ", s.length() "
                + s.length());
        int len = end - start;
        ensureCapacityInternal(count + len);
        for (int i = start, j = count; i < end; i++, j++)
            value[j] = s.charAt(i);
        count += len;
        return this;
    }
    
    @Override
    public AbstractStringBuilder append(char c) {
    
    
        ensureCapacityInternal(count + 1);
        value[count++] = c;
        return this;
    }
}

StringBuilder中的Override并不是重写,它调用的还是父类AbstractStringBuilder的方法,所以他是个指挥者

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
    
    
    @Override
    public StringBuilder append(String str) {
    
    
        super.append(str);
        return this;
    } 
}	

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

在这里插入图片描述

7.4 建造者模式的注意事项和细节

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

抽象工厂模式 VS 建造者模式

  • 抽象工厂模式实现对一个产品家族的创建;产品家族具有不同分类维度的产品组合,抽象工厂模式不需要关心构建过程,只关心产品由什么工厂生产。
  • 建造者模式则是需要按照指定的产品生产过程来构建产品,它主要目的是通过组装零配件而产生一个新产品

猜你喜欢

转载自blog.csdn.net/qq_45408390/article/details/131482813