资讯详情

23种设计模式之建造者模式

文章目录

  • 模型的定义和特征
  • 模式的由来
    • 实现方式
    • 使用方式
  • 模型的结构和实现
    • 模式的结构
    • 模式的实现
  • 模型应用场景
  • 建筑模式与工厂模式的区别
  • 模式的扩展
  • lombok的@Builder实现建造者模式的注释
    • 使用位置
Java技术债务

在软件开发过程中,有时需要创建一个复杂的对象,通常由多个子组件组成。例如,计算机是由的 CPU、如果由主板、内存、硬盘、显卡、底盘、显示器键盘、鼠标等部件组装而成,买家不能自己组装电脑,而是告诉电脑销售公司电脑的配置要求。电脑销售公司安排技术人员组装电脑,然后交给想买电脑的买家。

生活中有很多这样的例子,比如游戏中的不同角色,他们的性别、个性、能力、脸型、体型、服装、发型等特点不同;汽车中有各种各样的方向盘、发动机、框架、轮胎等部件;每封电子邮件的发件人、收件人、主题、内容、附件等内容也不同。

以上所有这些产品都是由多个部件构成的,各个部件可以灵活选择,但其创建步骤都大同小异。这类产品的创建无法用前面介绍的工厂模式描述,只有建造者模式可以很好地描述该类产品的创建。

模型的定义和特征

建造者(Builder)模式的定义:将复杂对象的结构与其表示分离,使相同的结构过程能够创建不同的表示,称为

它将一个复杂的对象分解成多个简单的对象,然后逐步构建。它将变相分离,即产品的组成部分不变,但每个部分都可以灵活选择。

  1. 封装性好,施工和表示分离。
  2. 扩展性好,各具体建造者相互独立,有利于系统的解耦。
  3. 客户端不需要知道产品内部组成的细节。施工人员可以在不影响其他模块的情况下逐步细化创建过程,以便于控制细节风险。

  1. 产品的组成部分必须相同,这限制了其使用范围。
  2. 若产品内部变化复杂,若产品内部内部发生变化,施工人员也应同时修改,后期维护成本较高。

建造者(Builder)不同的关注模式和工厂模式:

模式的由来

当一个类的构造函数参数超过4个,其中一些是可选的,我们通常有两种方法来构建它的对象。 例如,我们现在有以下类别的计算机Computer,其中cpu与ram是必填参数,其他三个是可选参数,那么我们如何构建这类实例呢?通常有两种常见的方法

public class Computer { 
             private String cpu;//必须     private String ram;//必须     private int usbCount;//可选     private String keyboard;//可选     private String display;//可选 } 

第一:折叠构造函数模式(telescoping constructor pattern ),我们经常使用这个,如下面的代码所示

public class Computer { 
              ...     public Computer(String cpu, String ram) { 
                 this(cpu, ram, 0);     }     public Computer(String cpu, String ram, int usbCount) { 
                 this(cpu, ram, usbCount, "罗技键盘");
    }
    public Computer(String cpu, String ram, int usbCount, String keyboard) { 
        
        this(cpu, ram, usbCount, keyboard, "三星显示器");
    }
    public Computer(String cpu, String ram, int usbCount, String keyboard, String display) { 
        
        this.cpu = cpu;
        this.ram = ram;
        this.usbCount = usbCount;
        this.keyboard = keyboard;
        this.display = display;
    }
}

第二种:Javabean 模式,如下所示

public class Computer { 
        
        ...

    public String getCpu() { 
        
        return cpu;
    }
    public void setCpu(String cpu) { 
        
        this.cpu = cpu;
    }
    public String getRam() { 
        
        return ram;
    }
    public void setRam(String ram) { 
        
        this.ram = ram;
    }
    public int getUsbCount() { 
        
        return usbCount;
    }
...
}

第一种主要是使用及阅读不方便。你可以想象一下,当你要调用一个类的构造函数时,你首先要决定使用哪一个,然后里面又是一堆参数,如果这些参数的类型很多又都一样,你还要搞清楚这些参数的含义,很容易就传混了。。。那酸爽谁用谁知道。

第二种方式在构建过程中对象的状态容易发生变化,造成错误。因为那个类中的属性是分步设置的,所以就容易出错。

为了解决这两个痛点,builder模式就横空出世了。

实现方式

  1. 在Computer 中创建一个静态内部类 Builder,然后将Computer 中的参数都复制到Builder类中。
  2. 在Computer中创建一个private的构造函数,参数为Builder类型
  3. 在Builder中创建一个public的构造函数,参数为Computer中必填的那些参数,cpu 和ram。
  4. 在Builder中创建设置函数,对Computer中那些可选参数进行赋值,返回值为Builder类型的实例
  5. 在Builder中创建一个build()方法,在其中构建Computer的实例并返回
public class Computer { 
        
    private final String cpu;//必须
    private final String ram;//必须
    private final int usbCount;//可选
    private final String keyboard;//可选
    private final String display;//可选

    private Computer(Builder builder){ 
        
        this.cpu=builder.cpu;
        this.ram=builder.ram;
        this.usbCount=builder.usbCount;
        this.keyboard=builder.keyboard;
        this.display=builder.display;
    }
    public static class Builder{ 
        
        private String cpu;//必须
        private String ram;//必须
        private int usbCount;//可选
        private String keyboard;//可选
        private String display;//可选

        public Builder(String cup,String ram){ 
        
            this.cpu=cup;
            this.ram=ram;
        }

        public Builder setUsbCount(int usbCount) { 
        
            this.usbCount = usbCount;
            return this;
        }
        public Builder setKeyboard(String keyboard) { 
        
            this.keyboard = keyboard;
            return this;
        }
        public Builder setDisplay(String display) { 
        
            this.display = display;
            return this;
        }        
        public Computer build(){ 
        
            return new Computer(this);
        }
    }
  //省略getter方法
}

使用方式

//在客户端使用链式调用,一步一步的把对象构建出来。
Computer computer=new Computer.Builder("因特尔","三星")
                .setDisplay("三星24寸")
                .setKeyboard("罗技")
                .setUsbCount(2)
                .build();

模式的结构与实现

建造者(Builder)模式由产品、抽象建造者、具体建造者、指挥者等 4 个要素构成,现在我们来分析其基本结构和实现方法。

模式的结构

建造者(Builder)模式的主要角色如下。

  1. 产品角色(Product):它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件。
  2. 抽象建造者(Builder):它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult()。
  3. 具体建造者(Concrete Builder):实现 Builder 接口,完成复杂产品的各个部件的具体创建方法。
  4. 指挥者(Director):它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥者中不涉及具体产品的信息。

模式的实现

其相关类的代码如下。

(1) 产品角色:包含多个组成部件的复杂对象。

class Product { 
        
    private String partA;
    private String partB;
    private String partC;

    public void setPartA(String partA) { 
        
        this.partA = partA;
    }

    public void setPartB(String partB) { 
        
        this.partB = partB;
    }

    public void setPartC(String partC) { 
        
        this.partC = partC;
    }

    public void show() { 
        
        //显示产品的特性
    }
}

(2) 抽象建造者:包含创建产品各个子部件的抽象方法。

abstract class Builder { 
        
    //创建产品对象
    protected Product product = new Product();
    public abstract void buildPartA();
    public abstract void buildPartB();
    public abstract void buildPartC();
    //返回产品对象
    public Product getResult() { 
        
        return product;
    }
}

(3) 具体建造者:实现了抽象建造者接口。

public class ConcreteBuilder extends Builder { 
        
    public void buildPartA() { 
        
        product.setPartA("建造 PartA");
    }
    public void buildPartB() { 
        
        product.setPartB("建造 PartB");
    }
    public void buildPartC() { 
        
        product.setPartC("建造 PartC");
    }
}

(4) 指挥者:调用建造者中的方法完成复杂对象的创建。

class Director { 
        
    private Builder builder;
    public Director(Builder builder) { 
        
        this.builder = builder;
    }
    //产品构建与组装方法
    public Product construct() { 
        
        builder.buildPartA();
        builder.buildPartB();
        builder.buildPartC();
        return builder.getResult();
    }
}

(5) 客户类。

public class Client { 
        
    public static void main(String[] args) { 
        
        Builder builder = new ConcreteBuilder();
        Director director = new Director(builder);
        Product product = director.construct();
        product.show();
    }
}

模式的应用场景

建造者模式唯一区别于工厂模式的是针对复杂对象的创建。也就是说,如果创建简单对象,通常都是使用工厂模式进行创建,而如果创建复杂对象,就可以考虑使用建造者模式。

当需要创建的产品具备复杂创建过程时,可以抽取出共性创建过程,然后交由具体实现类自定义创建流程,使得同样的创建行为可以生产出不同的产品,分离了创建与表示,使创建产品的灵活性大大增加。

建造者模式主要适用于以下应用场景:

  • 相同的方法,不同的执行顺序,产生不同的结果。
  • 多个部件或零件,都可以装配到一个对象中,但是产生的结果又不相同。
  • 产品类非常复杂,或者产品类中不同的调用顺序产生不同的作用。
  • 初始化一个对象特别复杂,参数多,而且很多参数都具有默认值。

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

  • 建造者模式更加注重方法的调用顺序,工厂模式注重创建对象。
  • 创建对象的力度不同,建造者模式创建复杂的对象,由各种复杂的部件组成,工厂模式创建出来的对象都一样
  • 关注重点不一样,工厂模式只需要把对象创建出来就可以了,而建造者模式不仅要创建出对象,还要知道对象由哪些部件组成。
  • 建造者模式根据建造过程中的顺序不一样,最终对象部件组成也不一样。

模式的扩展

建造者(Builder)模式在应用过程中可以根据需要改变,如果创建的产品种类只有一种,只需要一个具体建造者,这时可以省略掉抽象建造者,甚至可以省略掉指挥者角色。

lombok的@Builder注解实现建造者模式

@Builder自lombok v1.16.8起,使用可以添加明确的方法

@Builder注解为你的类提供复杂的建造者模式 API。

@Builder 使你可以自动生成使您的类可实例化的代码,例如:

Person.builder()
  .name("AdamSavage")
  .city("SanFrancisco")
  .job("Mythbusters")
  .job("Unchained Reaction")
  .build();

使用位置

@Builder可以放在类,构造器或方法上。虽然“基于类”和“基于构造器”模式是最常见的用例,但使用“方法”用例最容易解释。

🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽

本文作者:Java技术债务 原文链接:https://www.cuizb.top/myblog/article/1656947737 版权声明: 本博客所有文章除特别声明外,均采用 CC BY 3.0 CN协议进行许可。转载请署名作者且注明文章出处。

🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽🔽 JVM内存泄漏和内存溢出的原因 JVM常用监控工具解释以及使用 Redis 常见面试题(一) ClickHouse之MaterializeMySQL引擎(十) 三种实现分布式的实现与区别 线程池的理解以及使用

最近面试BAT,整理一份面试资料,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。想获取吗?如果你想提升自己,并且想和优秀的人一起进步,感兴趣的朋友,可以在扫码关注下方公众号。资料在公众号里静静的躺着呢。。。

————————————————————————————————————————————————————————————————

标签: 3d传感器于unchained

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

 锐单商城 - 一站式电子元器件采购平台  

 深圳锐单电子有限公司