【设计模式】建造者模式

创建一个对象,必定要设置该对象的属性,简单的对象还好,但一个复杂的对象具有很多复杂的属性,每次我们创建一个复杂对象后还需要设置它大量的属性,这显然浪费了时间。为了解决这个问题,我们可以考虑给该对象的属性设置一个有效的默认值,这样就有了一套默认的模板,我们创建对象时就只需要创建这个模板就行。但是,我们想要要多套默认的模板该怎么办呢?这个时候就可以通过设计模式来实现。

文章目录

  • 介绍
  • 工厂模式与建造者的区别
  • 建造者模式的使用
    • 类图
    • 实现方法
      • 第一步,创建食物类和套餐类
          • 食物类
          • 套餐类
      • 第二步,创建建造者类
          • 建造者类
      • 第三步,创建测试类测试
          • 测试类
          • 测试结果
  • 建造者模式的进一步优化使用
    • 类图
    • 实现方法
      • 第一步,创建食物类和套餐类
      • 第二步,创建建造者类
          • 套餐建造者类
      • 第三步,创建指挥者类
          • 指挥者类
      • 第四步,创建测试类测试
          • 测试类
          • 测试结果
  • 建造者模式的链式调用
      • Computer
      • Test

介绍

建造者模式主要解决一个复杂对象的创建工作,将其构建过程与表示过程进行分离,使其在相同的构建过程中可以创建出不同的模板。

工厂模式与建造者的区别

工厂模式和建造者模式都能帮助我们创建一个完整的对象,但工厂模式管理多个类,为多个类创建对象。而建造者模式只管理一个类,更重视对一个类的对象进行构建。

建造者模式的使用

以汉堡店的套餐为例,汉堡店中有多个套餐,每个套餐中有多个产品。现在我要创建一个套餐对象,但我不想一遍遍的设置该对象名称是什么,有哪些东西,价格是多少。于是我为套餐类添加一个建造者类来管理套餐对象。

类图

【设计模式】建造者模式_第1张图片

实现方法

第一步,创建食物类和套餐类

食物类
package 设计模式.建造者模式;

public class 食物类 {
    private String 名称;
    private Double 价格;

    public void 设置名称(String 名称) {
        this.名称 = 名称;
    }

    public void 设置价格(Double 价格) {
        this.价格 = 价格;
    }

    public String 获取名称() {
        return 名称;
    }

    public Double 获取价格() {
        return 价格;
    }
}
套餐类
package 设计模式.建造者模式;

import java.util.ArrayList;
import java.util.List;

public class 套餐类 {
    private String 套餐名;
    private List<食物类> 食物列表 = new ArrayList<>();
    private Double 价格;

    public void 设置套餐名(String 套餐名){
        this.套餐名 = 套餐名;
    }

    public void 添加食物(食物类 食物){
        食物列表.add(食物);
    }

    public void 展示套餐(){
        System.out.println(套餐名 + ":");
        价格 = 0d;
        for (食物类 食物 : 食物列表) {
            System.out.println("  " + 食物.获取名称() + "\t单价:" + 食物.获取价格());
            价格 += 食物.获取价格();
        }
        System.out.println("套餐价格:" + 价格);
    }
}

第二步,创建建造者类

建造者类
package 设计模式.建造者模式;

public class 建造者类 {

    public 套餐类 构造小霸王套餐(){
        套餐类 小霸王 = new 套餐类();
        小霸王.设置套餐名("小霸王套餐");
        // 创建食物——霸王鸡腿堡
        食物类 食物 = new 食物类();
        食物.设置名称("霸王鸡腿堡");
        食物.设置价格(12d);
        // 为套餐添加食物
        小霸王.添加食物(食物);
        // 创建食物——薯条
        食物 = new 食物类();
        食物.设置名称("薯条");
        食物.设置价格(10d);
        // 为套餐添加食物
        小霸王.添加食物(食物);
        // 创建食物——可乐
        食物 = new 食物类();
        食物.设置名称("中杯可乐");
        食物.设置价格(4.5);
        // 为套餐添加食物
        小霸王.添加食物(食物);
        return 小霸王;
    }

    public 套餐类 构造大霸王套餐(){
        套餐类 大霸王 = new 套餐类();
        大霸王.设置套餐名("大霸王套餐");
        // 创建食物——霸王鸡腿堡
        食物类 食物 = new 食物类();
        食物.设置名称("双层霸王鸡腿堡");
        食物.设置价格(16d);
        // 为套餐添加食物
        大霸王.添加食物(食物);
        // 创建食物——薯条
        食物 = new 食物类();
        食物.设置名称("薯条");
        食物.设置价格(10d);
        // 创建食物——上校鸡块
        食物 = new 食物类();
        食物.设置名称("上校鸡块");
        食物.设置价格(10d);
        // 为套餐添加食物
        大霸王.添加食物(食物);
        // 创建食物——可乐
        食物 = new 食物类();
        食物.设置名称("大杯可乐");
        食物.设置价格(4.5);
        // 为套餐添加食物
        大霸王.添加食物(食物);
        return 大霸王;
    }
}

第三步,创建测试类测试

测试类
package 设计模式.建造者模式;

public class 测试类 {
    public static void main(String[] args) {
        套餐类 套餐 = new 建造者类().构造小霸王套餐();
        套餐.展示套餐();
        System.out.println();
        套餐 = new 建造者类().构造大霸王套餐();
        套餐.展示套餐();
    }
}
测试结果

【设计模式】建造者模式_第2张图片



建造者模式的进一步优化使用

​ 通过上面的方法,我的确实现了构造与展示分离(所有的构造操作都在建造者类中完成,调用者无需关心构造的过程)。但此模式的结构还能优化,当前我们每添加一种套餐,就需要在建造者类中创建大量的食物对象,而这些食物对象(部分)价格和名称都是不变的,我们改变的只是套餐这个整体罢了,于是我想可以让建造者管理部分的创建,也就是添加各个食物,再创建一个指挥者类来管理整体套餐的创建,我们现在只用和指挥者沟通即可完成套餐的创建。

类图

【设计模式】建造者模式_第3张图片

实现方法

第一步,创建食物类和套餐类

​ 方法和之前的一样,没有改动

第二步,创建建造者类

套餐建造者类
package 设计模式.建造者模式.优化;

import 设计模式.建造者模式.套餐类;
import 设计模式.建造者模式.食物类;

public class 套餐建造者类 {

    private 套餐类 套餐;

    private 套餐建造者类(){
        // 可以直接在此方法中新建套餐,用new方法创建建造者。但我喜欢使用静态方法来创建,实现全部链式调用
    }

    /**
     * 初始化操作
     * @return
     */
    public static 套餐建造者类 准备套餐(){
        套餐建造者类 建造者 = new 套餐建造者类();
        建造者.套餐 = new 套餐类();
        return 建造者;
    }

    public 套餐建造者类 设置套餐名(String 套餐名){
        套餐.设置套餐名(套餐名);
        return this;
    }

    private void 添加食物(String 食物名, Double 价格){
        食物类 食物 = new 食物类();
        食物.设置名称(食物名);
        食物.设置价格(价格);
        套餐.添加食物(食物);
    }

    public 套餐建造者类 添加霸王鸡腿堡(){
        添加食物("霸王鸡腿堡",12d);
        return this;
    }

    public 套餐建造者类 添加双层霸王鸡腿堡(){
        添加食物("双层霸王鸡腿堡",16d);
        return this;
    }

    public 套餐建造者类 添加薯条(){
        添加食物("薯条",10d);
        return this;
    }

    public 套餐建造者类 添加上校鸡块(){
        添加食物("上校鸡块",10d);
        return this;
    }

    public 套餐建造者类 添加可乐(String 大小){
        // 模拟更复杂的创建方法
        String 名称 = 大小 + "可乐";
        Double 价格 = 4d;
        价格 = 大小.equals("小杯") ? 2d : 价格;
        价格 = 大小.equals("大杯") ? 5d : 价格;
        添加食物(名称, 价格);
        return this;
    }
    
    public 套餐类 建造完成(){
        return 套餐;
    }
}

第三步,创建指挥者类

指挥者类
package 设计模式.建造者模式.优化;

import 设计模式.建造者模式.套餐类;

public class 指挥者类 {

    public 套餐类 构造小霸王套餐(){
        return 套餐建造者类
                .准备套餐()
                .设置套餐名("小霸王套餐")
                .添加霸王鸡腿堡()
                .添加薯条()
                .添加可乐("小杯")
                .建造完成();
    }

    public 套餐类 构造大霸王套餐(){
        return 套餐建造者类.准备套餐()
                .设置套餐名("大霸王套餐")
                .添加双层霸王鸡腿堡()
                .添加上校鸡块()
                .添加可乐("中杯")
                .建造完成();
    }

    public 套餐类 构造至尊大霸王套餐(){
        return 套餐建造者类.准备套餐()
                .设置套餐名("至尊大霸王套餐")
                .添加双层霸王鸡腿堡()
                .添加上校鸡块()
                .添加薯条()
                .添加可乐("大杯")
                .建造完成();
    }
}

第四步,创建测试类测试

测试类
package 设计模式.建造者模式;

import 设计模式.建造者模式.优化.指挥者类;

public class 测试类 {
    public static void main(String[] args) {
        套餐类 套餐 = new 指挥者类().构造小霸王套餐();
        套餐.展示套餐();
        System.out.println();
        套餐 = new 指挥者类().构造大霸王套餐();
        套餐.展示套餐();
        System.out.println();
        套餐 = new 指挥者类().构造至尊大霸王套餐();
        套餐.展示套餐();
    }
}

测试结果

【设计模式】建造者模式_第4张图片

建造者模式的链式调用

​ 使用链式调用方法可以非常方便的完成一个对象的创建。

Computer

package 设计模式.建造者模式.链式调用;

public class Computer {

    private String cpu;
    private String videoCard;
    private String memory;
    private String storageSpaces;

    private Computer(Builder builder){
            cpu = builder.cpu;
            videoCard = builder.videoCard;
            memory = builder.memory;
            storageSpaces = builder.storageSpaces;
    }

    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", videoCard='" + videoCard + '\'' +
                ", memory='" + memory + '\'' +
                ", storageSpaces='" + storageSpaces + '\'' +
                '}';
    }

    public static class Builder{
        private String cpu;
        private String videoCard;
        private String memory;
        private String storageSpaces;

        public Builder setCpu(String cpu) {
            this.cpu = cpu;
            return this;
        }

        public Builder setVideoCard(String videoCard) {
            this.videoCard = videoCard;
            return this;
        }

        public Builder setMemory(String memory) {
            this.memory = memory;
            return this;
        }

        public Builder setStorageSpaces(String storageSpaces) {
            this.storageSpaces = storageSpaces;
            return this;
        }

        public Computer build(){
            return new Computer(this);
        }
    }

}

Test

package 设计模式.建造者模式.链式调用;

public class Test {
    public static void main(String[] args) {
        Computer computer = new Computer.Builder().setCpu("CORE i7-9750")
                .setMemory("16GB")
                .setVideoCard("GTX1660 Ti 6G")
                .setStorageSpaces("1TB SSD + 1TB HDD")
                .build();
        System.out.println(computer);
    }
}
       }
    }

}

你可能感兴趣的:(设计模式,建造者模式,java)