建造者模式(Builder Pattern)

概念

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一。Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的,相当于聚合其他的类,完成最终可供选择的产品;这里可以抽象为表示与构建过程进行分离,客户端只需关注表示出来的东西;

简介

作用及优势

    - 将复杂的构建过程与最终需要表示的东西分开来

    - 根据表示层的需求,可以利用一些不变的东西去随意组装

    - 解耦,把复杂对象的构建过程,拆分成具有独立功能的类(类似零件 的存在),然后再进行组装

    - 灵活性、重用性高,根据需求的变更,可以给出不同的组合;

不足之处

    - 这一类元件大部分只能组装成一个系列的产品;

    - 零件 越多,证明需要创建的类越多,这样之前的组装好的建造者,可能也需要随之改变;

    

应用实例

    - 建造者模式的经典案例就是lombok的@Builder注解,提供建造者模式去构建自己最后想要的对象,这里没有用的小伙伴可以去试试;

    - 通过积木可以组装成各类房子

    - java的StringBuilder

代码

案例描述

有个电脑店(ComputerBuilder),他有很多材料可以使用,最后需要给出几套方案:有高配的、中配的、低配的;顾客想买的话就直接提走就行了,不需要自己组装电脑(当然向我们程序员肯定是要自己体验组装的乐趣了😁),这大概就是建造者模式的概念;

工程目录

image.png

项目类图

建造者.jpg

具体实现

材料抽象类(Material) :提供了一些属性用于子类复用;

/**
 * @author chengxing.wu
 * @date 2021/6/17
 */
public abstract class Material {
    /**
     * 品牌
     */
    protected String brand;

    /**
     * 价格
     */
    protected BigDecimal price;

    /**
     * 大小
     */
    protected String size;

    /**
     * 描述
     */
    protected String desc;

    protected Material(String brand, BigDecimal price, String size, String desc) {
        this.brand = brand;
        this.price = price;
        this.size = size;
        this.desc = desc;
    }
}

产品抽象类 :CPU、Memory、Disk

public class CPU extends Material {

    protected CPU(String brand, BigDecimal price, String size, String desc) {
        super(brand, price, size, desc);
    }
}

-----------------------------------

public class Memory extends Material {

    protected Memory(String brand, BigDecimal price, String size, String desc) {
        super(brand, price, size, desc);
    }
} 

------------------------------------

public class Disk extends Material {

    protected Disk(String brand, BigDecimal price, String size, String desc) {
        super(brand, price, size, desc);
    }
} 

cpu具体实现(intel)

public class Intel extends CPU {

    protected Intel(String brand, BigDecimal price, String size, String desc) {
        super(brand, price, size, desc);
    }

    protected Intel(String brand, BigDecimal price, String size) {
        this(brand, price, size, "Intel-我就是喜欢挤牙膏...");
    }

    static class IntelFactory {
        public static CPU create(String level) {
            if (BuilderConstant.LEVEL_HIGH.equals(level)) {
                return getHighIntel();
            } else if (BuilderConstant.LEVEL_MID.equals(level)) {
                return getMidIntel();
            } else if (BuilderConstant.LEVEL_LOW.equals(level)) {
                return getLowIntel();
            } else {
                return null;
            }
        }

        public static Intel getHighIntel() {
            return new Intel("Intel-i9750H", new BigDecimal("2000"), "标压");
        }

        public static Intel getMidIntel() {
            return new Intel("Intel-i8750H", new BigDecimal("1500"), "标压");
        }

        public static Intel getLowIntel() {
            return new Intel("Intel-U5500", new BigDecimal("800"), "低压");
        }
    }
}

tips: 这里面应该将每一种规格的Intel都抽离出来的,但是过于臃肿,所以这里选择使用工厂方法去实现多规格产品;

Memory的具体实现(Samsung) :跟cpu的实现原理一样;

public class Samsung extends Memory {

    protected Samsung(String brand, BigDecimal price, String size, String desc) {
        super(brand, price, size, desc);
    }

    protected Samsung(String brand, BigDecimal price, String size) {
        this(brand, price, size, "三星-性能好,我不会爆炸的...");
    }

    /**
     * 这些类可以抽出来 结合抽象工厂来实现 分为不同的 类型模板,这里用的是 工厂方法
     */
    static class SamsungFactory {
        public static Memory create(String level) {
            if (BuilderConstant.LEVEL_HIGH.equals(level)) {
                return getHighIntel();
            } else if (BuilderConstant.LEVEL_MID.equals(level)) {
                return getMidIntel();
            } else if (BuilderConstant.LEVEL_LOW.equals(level)) {
                return getLowIntel();
            } else {
                return null;
            }
        }

        public static Samsung getHighIntel() {
            return new Samsung("Samsung-DDR4-3200", new BigDecimal("1200"), "32GB");
        }

        public static Samsung getMidIntel() {
            return new Samsung("Samsung-DDR4-2666", new BigDecimal("1100"), "32GB");
        }

        public static Samsung getLowIntel() {
            return new Samsung("Samsung-DDR4-2666", new BigDecimal("600"), "16GB");
        }
    }
}

Disk的的具体实现(Kingston) :跟cpu的实现原理一样;

public class Kingston extends Disk {

    protected Kingston(String brand, BigDecimal price, String size, String desc) {
        super(brand, price, size, desc);
    }

    protected Kingston(String brand, BigDecimal price, String size) {
        this(brand, price, size, "金士顿-性能好,就是稍微贵点...");
    }

    static class KingstonFactory {
        public static Disk create(String level) {
            if (BuilderConstant.LEVEL_HIGH.equals(level)) {
                return getHighIntel();
            } else if (BuilderConstant.LEVEL_MID.equals(level)) {
                return getMidIntel();
            } else if (BuilderConstant.LEVEL_LOW.equals(level)) {
                return getLowIntel();
            } else {
                return null;
            }
        }

        public static Kingston getHighIntel() {
            return new Kingston("Kingston-m.2-a400", new BigDecimal("700"), "1024GB");
        }

        public static Kingston getMidIntel() {
            return new Kingston("Kingston-m.2-sata总线", new BigDecimal("380"), "512GB");
        }

        public static Kingston getLowIntel() {
            return new Kingston("Kingston-sata3.0", new BigDecimal("300"), "512GB");
        }
    }
}

电脑构建工厂(ComputerBuilder)

public class ComputerBuilder {

    public static void builder(String level) {
        if (BuilderConstant.LEVEL_HIGH.equals(level)) {
            highBuilder();
        } else if (BuilderConstant.LEVEL_MID.equals(level)) {
            midBuilder();
        } else if (BuilderConstant.LEVEL_LOW.equals(level)) {
            lowBuilder();
        }
    }

    /**
     * 这些builder可以作为子建造者,以集成的方式做,类似于工厂,之后想增加新的构建的时候,只要新加类就行,不会对代码造成侵入
     *
     * @return
     */
    private static void highBuilder() {
        CPU cpu = Intel.IntelFactory.create(BuilderConstant.LEVEL_HIGH);
        Disk disk = Kingston.KingstonFactory.create(BuilderConstant.LEVEL_HIGH);
        Memory memory = Samsung.SamsungFactory.create(BuilderConstant.LEVEL_HIGH);
        printLevel(cpu, disk, memory, "high");
    }

    private static void midBuilder() {
        CPU cpu = Intel.IntelFactory.create(BuilderConstant.LEVEL_MID);
        Disk disk = Kingston.KingstonFactory.create(BuilderConstant.LEVEL_MID);
        Memory memory = Samsung.SamsungFactory.create(BuilderConstant.LEVEL_MID);
        printLevel(cpu, disk, memory, "mid");
    }

    private static void lowBuilder() {
        CPU cpu = Intel.IntelFactory.create(BuilderConstant.LEVEL_LOW);
        Disk disk = Kingston.KingstonFactory.create(BuilderConstant.LEVEL_LOW);
        Memory memory = Samsung.SamsungFactory.create(BuilderConstant.LEVEL_LOW);
        printLevel(cpu, disk, memory, "low");
    }

    private static void printLevel(CPU cpu, Disk disk, Memory memory, String type) {
        BigDecimal decimal = Objects.requireNonNull(cpu)
                .price.add(Objects.requireNonNull(disk)
                        .price.add(Objects.requireNonNull(memory).price));
        System.out.println("========== " + type.toUpperCase() + " ===========");
        System.out.println("========== CPU:" + cpu.brand + "/" + cpu.brand + "/"
                + cpu.size + "/" + cpu.desc + ", " + "价格:===> " + cpu.price + " ===========");
        System.out.println("========== DISK:" + disk.brand + "/" + disk.brand + "/"
                + disk.size + "/" + disk.desc + ", " + "价格:===> " + disk.price +  " ===========");
        System.out.println("========== MEMORY:" + memory.brand + "/" + memory.brand + "/"
                + memory.size + "/" + memory.desc + ", " + "价格:===> " + memory.price +  " ===========");
        System.out.println(type + "--价格(总价):===> " + decimal);
    }
}

这里有点类似用工厂去管理各种建造者(highBuilder、midBuilder、lowBuilder);每个构建者都是由零件组装而成;然后就交由工厂管理,大概就是这样的设计;

常量类: BuilderConstant

public class BuilderConstant {
    /**
     * 低配
     */
    public static final String LEVEL_LOW = "low";

    /**
     * 中配
     */
    public static final String LEVEL_MID = "mid";

    /**
     * 高配
     */
    public static final String LEVEL_HIGH = "high";
}

测试

public class BuilderTest {
    public static void main(String[] args) {
        ComputerBuilder.builder(BuilderConstant.LEVEL_LOW);
        ComputerBuilder.builder(BuilderConstant.LEVEL_MID);
        ComputerBuilder.builder(BuilderConstant.LEVEL_HIGH);
    }
}

结果: 可以看出这里组合成了三种价位,除此之外,我们可以根据用户提出来的需求再次组装,而不会影响之前的代码逻辑;且这些产品信息也是可以复用的;

========== LOW ===========
========== CPU:Intel-U5500/Intel-U5500/低压/Intel-我就是喜欢挤牙膏..., 价格:===> 800 ===========
========== DISK:Kingston-sata3.0/Kingston-sata3.0/512GB/金士顿-性能好,就是稍微贵点..., 价格:===> 300 ===========
========== MEMORY:Samsung-DDR4-2666/Samsung-DDR4-2666/16GB/三星-性能好,我不会爆炸的..., 价格:===> 600 ===========
low--价格(总价):===> 1700
========== MID ===========
========== CPU:Intel-i8750H/Intel-i8750H/标压/Intel-我就是喜欢挤牙膏..., 价格:===> 1500 ===========
========== DISK:Kingston-m.2-sata总线/Kingston-m.2-sata总线/512GB/金士顿-性能好,就是稍微贵点..., 价格:===> 380 ===========
========== MEMORY:Samsung-DDR4-2666/Samsung-DDR4-2666/32GB/三星-性能好,我不会爆炸的..., 价格:===> 1100 ===========
mid--价格(总价):===> 2980
========== HIGH ===========
========== CPU:Intel-i9750H/Intel-i9750H/标压/Intel-我就是喜欢挤牙膏..., 价格:===> 2000 ===========
========== DISK:Kingston-m.2-a400/Kingston-m.2-a400/1024GB/金士顿-性能好,就是稍微贵点..., 价格:===> 700 ===========
========== MEMORY:Samsung-DDR4-3200/Samsung-DDR4-3200/32GB/三星-性能好,我不会爆炸的..., 价格:===> 1200 ===========
high--价格(总价):===> 3900