建造者模式深入理解:演示建造单个和多个产品的实践,结合模板模式,通俗易懂

首先呢看下建造者的定义是什么样的,先读一遍

建造者模式

建造者模式(Builder Pattern)是一种创建型设计模式,它主要用于将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表现形式。这种模式通过一系列可重用的独立的类(称为建造者或构建器)来一步一步创建一个复杂的对象,而不需要知道具体的内部构造细节

优缺点

建造者模式的主要优点

  1. 封装性好:通过建造者将产品的各个部件和组装过程封装起来,客户端无需了解产品内部的具体构造细节,只需指定需要的产品类型和配置即可。
  2. 扩展性好:由于每个具体建造者都是相互独立的,因此新增一种产品或者变更已有产品的构建方式时,只需要新增或修改相应的建造者类,不影响其他部分代码,从而实现系统的松耦合。
  3. 便于控制构建过程:在构建过程中,可以根据需要逐步细化构造步骤,灵活地控制产品的创建过程,甚至支持动态决定构建部件的数量和顺序。
  4. 便于并行构造:在某些场景下,不同部分的构建可以独立进行,有利于提高系统性能,特别是在多线程环境下的构建。

建造者模式的主要缺点

  1. 增加类的数量:引入建造者模式会增加额外的类,包括抽象建造者、具体建造者和可能的导演类等,增加了系统的复杂性和理解难度。
  2. 内部修改困难:一旦产品结构较为复杂,对于产品内部细节的改动可能会导致多个建造者的相关逻辑都需要调整,维护成本相对较高。
  3. 过度设计风险:如果对象结构比较简单,或者变化不多,使用建造者模式可能会显得过于复杂,不适用于简单对象的构建。
    总结来说,建造者模式非常适合用于创建具有多重构造参数或组合选项的复杂对象,尤其当这些选项的不同组合可能导致大量微小差异的产品实例时,该模式能够很好地管理和组织这些复杂性。

网图来一张
在这里插入图片描述
好了,直接上代码,这里我们先构建一个CarProduct,很多描述都写在了对应的注释中了啊,这里就不过多赘述

package com.mtgg.laoxiang.service.example.designer.builder;

import lombok.Data;

/**
 * 要构建的产品对象
 */
@Data
public class CarProduct {
    private String partA;
    private String partB;
    private String partC;
}
package com.mtgg.laoxiang.service.example.designer.builder;

/**
 * 建造者抽象类
 */
public abstract class Builder {
    //建造产品时,实例化,相当于统一放到一个地方,product相当于一个封装,里面可以放各种东西的组成
    protected CarProduct carProduct = new CarProduct();


    //建造,建造各种东西然后set到product中
    public abstract void builderPartA();

    public abstract void builderPartB();

    public abstract void builderPartC();

    //提供获得产品的入口,要获得这个产品,就调用这个方法
    public CarProduct getResult() {
        return carProduct;
    }

}

上面定义了产品,构造器,获取产品的方法,下面这个就是构造器要具体干的活了

package com.mtgg.laoxiang.service.example.designer.builder;

public class BJBuilder extends Builder{

    @Override
    public void builderPartA() {
        System.out.println("构建个1球");
        carProduct.setPartA("1球");
    }

    @Override
    public void builderPartB() {
        System.out.println("构建个2球");
        carProduct.setPartB("2球");
    }

    @Override
    public void builderPartC() {
        System.out.println("构建个3球");
        carProduct.setPartC("3球");
    }
}

package com.mtgg.laoxiang.service.example.designer.builder;

public class HZBuilder extends Builder{

    @Override
    public void builderPartA() {
        System.out.println("构建个1香蕉");
        carProduct.setPartA("1香蕉");
    }

    @Override
    public void builderPartB() {
        System.out.println("构建个2香蕉");
        carProduct.setPartB("2香蕉");
    }

    @Override
    public void builderPartC() {
        System.out.println("构建个3香蕉");
        carProduct.setPartC("3香蕉");
    }
}

指挥者来了,指挥我到底想要啥,什么数量,什么顺序,定义几个图纸来交给构造器去构造,然后main使用的时候直接调用这个定义好的流程,就能拿到对应的产品

package com.mtgg.laoxiang.service.example.designer.builder;

/**
 * 指挥者
 * 控制生成流程
 */
public class Director {
    //这个抽象类可以定义成全局变量,也可以定义接口,此处可以引用接口,更不违反原则
    private Builder builder;

    /**
     * 注入builder
     */
    private Director(Builder builder) {
        this.builder = builder;
    }

    /**
     * 控制流程,此处类似使用模板模式
     */
    public CarProduct construct2(){
        builder.builderPartC();
        builder.builderPartA();
        return builder.getResult();
    }

    public CarProduct construct(){
        builder.builderPartB();
        builder.builderPartA();
        builder.builderPartC();
        return builder.getResult();
    }

    public static void main(String[] args) {
        //此处可选择不同的建造者建造产品
        Director director = new Director(new HZBuilder());
        CarProduct construct = director.construct();
        System.out.println(construct);

        director = new Director(new BJBuilder());
        CarProduct construct1 = director.construct2();
        System.out.println(construct1);
    }

}

*构建个2香蕉
构建个1香蕉
构建个3香蕉
Product(partA=1香蕉, partB=2香蕉, partC=3香蕉)
构建个3球
构建个1球
Product(partA=1球, partB=null, partC=3球) *

在这里插入图片描述

如果我想建造另外一个对象呢?难道类似的类都要加一份?那肯定是low的,做法如下,

可以加具体建造,定义好要建造的东西,再建一个指挥者方法,尽量不要在原来的方法上改,改造后如下

假如有另一个对象PhoneProduct

@Data
public class PhoneProduct {
    private String pa;
    private String pb;
    private String pc;
}

Builder中加上要构建的这个产品,并加个返回产品的方法,所以这么看的话那几个构建的抽象方法就不能太个性化,最好抽象一些,像是定义三四个工厂一样,具体怎么生产看子类实现

public abstract class Builder {
    //建造产品时,实例化,相当于统一放到一个地方,product相当于一个封装,里面可以放各种东西的组成

    //另外一个产品
    protected PhoneProduct phoneProduct = new PhoneProduct();
……………………

    public PhoneProduct getPhoneResult() {
        return phoneProduct;
    }
}

好了我们定义一个子类去构建具体的内容,不用改另外一个对象的构建,保证对扩展开放,对修改关闭

public class XMBuilder extends Builder{
    @Override
    public void builderPartA() {
        System.out.println("小米a");
        phoneProduct.setPa("pa");
    }

    @Override
    public void builderPartB() {
        System.out.println("小米b");
        phoneProduct.setPb("pb");
    }

    @Override
    public void builderPartC() {
        System.out.println("小米c");
        phoneProduct.setPc("pc");
    }
}

指挥者我们改造一下,构建顺序以及数量都可以抽出来共用,只需要定义construct2或constructPhone方法,指定模板,返回产品就OK了,想要啥产品要啥产品

public class Director {
    //这个抽象类可以定义成全局变量,也可以定义接口,此处可以引用接口,更不违反原则
    private Builder builder;

    /**
     * 注入builder
     */
    private Director(Builder builder) {
        this.builder = builder;
    }

    /**
     * 构建模板 定义构建顺序以及内容
     */
    public void buildTemplateA(){
        builder.builderPartB();
        builder.builderPartA();
        builder.builderPartC();
    }

    /**
     * 构建模板 定义构建顺序以及内容
     */
    public void buildTemplateB(){
        builder.builderPartC();
        builder.builderPartA();
    }

    /**
     * 构建以及获取car产品的入口
     */
    public CarProduct construct2(){
        this.buildTemplateB();
        return builder.getResult();
    }

	//不同形态的car产品
    public CarProduct construct(){
        this.buildTemplateA();
        return builder.getResult();
    }

	//这个是构建和获取phone产品的入口
    public PhoneProduct constructPhone(){
        this.buildTemplateA();
        return builder.getPhoneResult();
    }

    public static void main(String[] args) {
        //此处可选择不同的建造者建造产品
        Director director = new Director(new HZBuilder());
        CarProduct construct = director.construct();
        System.out.println(construct);

        director = new Director(new BJBuilder());
        CarProduct construct1 = director.construct2();
        System.out.println(construct1);

        //构建另外一个产品,使用时指定用XMBuilder这个厂家生产的就行
        director = new Director(new XMBuilder());
        PhoneProduct construct2 = director.constructPhone();
        System.out.println(construct2);
    }

}

下面这是执行结果

构建个2香蕉
构建个1香蕉
构建个3香蕉
CarProduct(partA=1香蕉, partB=2香蕉, partC=3香蕉)
构建个3球
构建个1球
CarProduct(partA=1球, partB=null, partC=3球)
小米b
小米a
小米c
PhoneProduct(pa=pa, pb=pb, pc=pc)

祝你好运!~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/327617.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

圈小猫游戏HTML源码

源码介绍 圈小猫游戏html源码,HTMLCSSJS,记事本可以打开修改内容,电脑本地双击index.html即可运行,也可以上传到服务器上面运行,喜欢的同学可以拿去使用 下载地址 蓝奏云:https://wfr.lanzout.com/iFkVc1lb5akj CS…

pytorch一致数据增强—独用增强

前作 [1] 介绍了一种用 pytorch 模仿 MONAI 实现多幅图(如:image 与 label)同用 random seed 保证一致变换的写法,核心是 MultiCompose 类和 to_multi 包装函数。不过 [1] 没考虑各图用不同 augmentation 的情况,如&am…

【C++】- 类和对象(构造函数!!explicit关键字stastic关键字!!详解)

类和对象④ 构造函数初始化列表explicit关键字static成员 构造函数初始化列表 我们已经初步了解了构造函数------->类和对象②那么调用构造函数就是给了对象中各个成员变量一个合适的初始值。 但实际上,我们想要做的是初始化成员变量,在构造函数中对…

新手学习指南:用Scala采集外卖平台

学习爬虫不是一蹴而就的,在掌握相关的知识点的同时,还要多加练习,学习是一部分,更多的还是需要自己上手操作,这里配合自己学习的基础,以及使用一些爬虫的专有库,就可以轻松达到自己想要的数据。…

Angular系列教程之自定义指令

文章目录 前言指令的基本概念在模板中使用指令总结 前言 在Angular中,指令是一种非常强大的工具,用于扩展HTML元素的功能和行为。它们允许我们创建可重用的组件,并在应用程序中的多个地方使用它们。本文将介绍Angular指令的基础知识&#xf…

【下云】旧笔记本实现私人服务器

背景&缘由&想法 背景: 自己是做Java的,做互联网或者说学计算机的都知道,近几年大环境太差,人却越来越多,造成行业越来越卷;针对Java来说,被迫要学习多方面的知识,工作拧螺…

压力测试+接口测试(工具jmeter)

jmeter是apache公司基于java开发的一款开源压力测试工具,体积小,功能全,使用方便,是一个比较轻量级的测试工具,使用起来非常简单。因 为jmeter是java开发的,所以运行的时候必须先要安装jdk才可以。jmeter是…

3.0.0 网络安全技术

一、端口安全 1、端口隔离 1.1 简介 以太交换网络中为了实现报文之间的二层隔离,用户通常将*不同的端口*加入*不同的VLAN*,实现二层广播域的隔离。只通过VLAN实现报文二层隔离,会浪费有限的VLAN资源,同时也只能实现基础的隔离操…

Python基础知识:整理17 -> 类和对象

1 初识对象 # 1. 设计一个类: 类的属性->成员变量、 类的行为->成员方法 class Student:name None # 记录学生姓名gender None # 记录学生性别age None # 记录学生年龄score None # 记录学生成绩def say(self): # 成员方法return (f"hel…

工业平板定制方案_基于联发科、紫光展锐平台的工业平板电脑方案

工业平板主板采用联发科MT6762平台方案,搭载Android 11.0操作系统, 主频最高2.0GHz,效能有大幅提升;采用12nm先进工艺,具有低功耗高性能的特点。 该工业平板主板搭载了IMG GE8320图形处理器,最高主频为680MHz, 支持108…

019、错误处理:不可恢复错误与panic!

鉴于上一篇文章过长,不方便大家阅读和理解,因此关于Rust中的错误处理, 我将分以下3篇来讲。 另外,随着我们学习的不断深入,难度也会越来越大,但不用担心。接下来只需要让自己的脚步慢一些,认真搞…

软件测试|教你如何使用Python绘制出奥运五环旗

简介 我们之前介绍过使用turtle来绘制正多边形,但是绘制正多边形只是turtle模块最基础的使用,我们可以使用turtle模块绘制出更多不一样的精彩图形,本文就来给大家介绍一个比较简单的turtle绘图实例,绘制奥运五环旗。 初始化参数…

JS | JS调用EXE

JS | JS调用EXE 网上洋洋洒洒一大堆文章提供,然我还是没找打合适的方案: 注册表方案做了如下测试(可行但是不推荐?): 先,键入文件名为 myprotocal.reg 的注册表,并键入一下信息: Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\openExe] //协议名…

[开发语言][c++]:Static关键字和全局变量

Static关键字和全局变量 1. 生命周期、作用域和初始化时机2. 全局变量3. Static 关键字3.1 面向过程3.1.1 静态全局变量3.1.2 静态局部变量(单例中会使用)3.1.3 静态函数 3.2 面向对象3.2.1 类内静态成员变量3.2.2 类内静态成员函数 Reference 写在前面&…

有n个水塔,初始每个水塔有a[i]的水,每个水塔一次最多拿b[i]的水,现从1~n依次在水塔中取水,没取完的水全部流入下一个水塔,求最终能取多少水

题目 思路&#xff1a; 假设有两个水塔1和2&#xff0c;分类讨论&#xff1a; 1、当a1 > b1时&#xff0c;2中剩下的水是a2 - b2 a1 - b1 2、当a1 < b1时&#xff0c;1中的水不会流到2中&#xff0c;2中剩下的水是a2 - b2 即最大&#xff08;a - b) 的后缀和 #incl…

【数字电子技术课程设计】多功能数字电子钟的设计

目录 摘要 1 设计任务要求 2 设计方案及论证 2.1 任务分析 2.1.1 晶体振荡器电路 2.1.2 分频器电路 2.1.3 时间计数器电路 2.1.4 译码驱动电路 2.1.5 校时电路 2.1.6 整点报时/闹钟电路 2.2 方案比较 2.3 系统结构设计 2.4 具体电路设计 3 电路仿真测试及结…

CMake tasks.json launch.json

hehedalinux:~/Linux/cmake/cmakeClass$ tree . ├── CMakeLists.txt ├── include │ ├── Gun.h │ └── Soldier.h ├── main.cpp └── src├── Gun.cpp└── Soldier.cpp2 directories, 6 files hehedalinux:~/Linux/cmake/cmakeClass$ launch.json&am…

linux主机的免密登录

实现linux主机之间的相互免密登录 在进行远程登录的时&#xff0c;服务器和主机间进行认证阶段分为&#xff1a; 基于口令认证&#xff08;不安全&#xff0c;易被抓包拦截获取&#xff09; 客户机连接服务器时&#xff0c;服务器将自己的公钥返回给客户机 客户机会将服务器的…

【报错】NVIDIA 驱动版本不兼容 — NVIDIA driver on your system is too old

【报错】NVIDIA 驱动版本不兼容 — NVIDIA driver on your system is too old 报错信息查看torch版本查看nvidia驱动版本 报错信息 CUDA initialization: The NVIDIA driver on your system is too old (found version 11040). Please update your GPU driver by downloading …

29 旋转工具箱

效果演示 实现了一个菜单按钮的动画效果&#xff0c;当鼠标悬停在菜单按钮上时&#xff0c;菜单按钮会旋转315度&#xff0c;菜单按钮旋转的同时&#xff0c;菜单按钮旋转的8个小圆圈也会依次旋转360度&#xff0c;并且每个小圆圈的旋转方向和菜单按钮的旋转方向相反&#xff0…
最新文章