生成器模式详解:用法与示例

news2024/12/24 4:04:24

目录

  • 生成器模式
    • 生成器模式结构
    • 生成器模式应用场景
    • 生成器模式优缺点
    • 练手题目
      • 题目描述
      • 输入描述
      • 输出描述
      • 提示信息
      • 题解

生成器模式

生成器模式,又称建造者模式,是一种创建型设计模式, 使你能够分步骤创建复杂对象。该模式允许你使用相同的创建代码生成不同类型和形式的对象。

生成器模式结构

在这里插入图片描述

  1. 生成器(Builder)接口声明在所有类型生成器中通用的产品构造步骤。
  2. 具体生成器(Concrete Builders) 提供构造过程的不同实现。具体生成器也可以构造不遵循通用接口的产品。
  3. 产品(Products)是最终生成的对象。由不同生成器构造的产品无需属于同一类层次结构或接口。
  4. 主管(Director) 类定义调用构造步骤的顺序,这样你就可以创建和复用特定的产品配置。
  5. 客户端(Client) 必须将某个生成器对象与主管类关联。一般情况下,你只需通过主管类构造函数的参数进行一次性关联即可。 此后主管类就能使用生成器对象完成后续所有的构造任务。但在客户端将生成器对象传递给主管类制造方法时还有另一种方式。在这种情况下,你在使用主管类生产产品时每次都可以使用不同的生成器。

通用代码结构示例


//产品类
public class Product1{
	...
}

public class Product2{
	...
}

//抽象生成器类
public abstract interface Builder{
 public void reset();
//生成产品步骤
 public void buildStepA();
 public void buildStepB();
 public void buildStepC();
}

//具体生成器类
public class ConcreteBuilder1 implements Builder{
 private Product1 product1 ;
 
 // reset(重置)方法可清除正在生成的对象。
 public void reset(){
 this.product1=new Product1();
 }
 //生成产品步骤
 public void buildStepA(){
	 ...
 };
 public void buildStepB(){
	 ...
 };
 public void buildStepC(){
	 ...
 };
 //组建产品
 public Product1 buildProduct1(){
	 return this.product1;
 } 
}

public class ConcreteBuilder2 implements Builder{
 private Product2 product2 ;
 // reset(重置)方法可清除正在生成的对象。
 public void reset(){
 this.product2=new Product2();
 }
 //生成产品步骤
 public void buildStepA(){
	 ...
 };
 public void buildStepB(){
	 ...
 };
 public void buildStepC(){
	 ...
 };
 //组建产品
 public Product2 buildProduct2(){
	 return this.product2;
 } 
}

//导演类 责按照特定顺序执行生成步骤。其在根据特定步骤或配置来生成产品时会很有帮助。
//由于客户端可以直接控制生成器,所以严格意义上来说,该类并不是必需的。
public class Director{
private Builder builder = new ConcreteBulider();
public void getProduct(){
	builder.reset();
	...
}
}

//客户端
public class Client{
	Director director = new Director();
	ConcreteBuilder1 bulider1 = new ConcreteBuilder1();
	director.getProduct(bulider1);
	Product1 product1 = bulider1.buildProduct1();
}

生成器模式应用场景

  • 使用生成器模式可避免 “重叠构造函数 (telescoping constructor)” 的出现。

    假设你的构造函数中有十个可选参数, 那么调用该函数会非常不方便; 因此, 你需要重载这个构造函数, 新建几个只有较少参数的简化版。 但这些构造函数仍需调用主构造函数, 传递一些默认数值来替代省略掉的参数。

    生成器模式让你可以分步骤生成对象, 而且允许你仅使用必须的步骤。 应用该模式后, 你再也不需要将几十个参数塞进构造函数里了。

  • 当你希望使用代码创建不同形式的产品 (例如石头或木头房屋) 时, 可使用生成器模式。

    如果你需要创建的各种形式的产品, 它们的制造过程相似且仅有细节上的差异, 此时可使用生成器模式。基本生成器接口中定义了所有可能的制造步骤, 具体生成器将实现这些步骤来制造特定形式的产品。 同时, 主管类将负责管理制造步骤的顺序。

  • 使用生成器构造组合树或其他复杂对象。

    生成器模式让你能分步骤构造产品。 你可以延迟执行某些步骤而不会影响最终产品。 你甚至可以递归调用这些步骤, 这在创建对象树时非常方便。生成器在执行制造步骤时, 不能对外发布未完成的产品。 这可以避免客户端代码获取到不完整结果对象的情况。

在这里插入图片描述

识别方法:生成器模式可以通过类来识别, 它拥有一个构建方法和多个配置结果对象的方法。 生成器方法通常支持方法链 (例如 someBuilder.setValueA(1).setValueB(2).create())。

生成器模式优缺点

优点:

  • 你可以分步创建对象, 暂缓创建步骤或递归运行创建步骤。
  • 生成不同形式的产品时, 你可以复用相同的制造代码。
  • 单一职责原则。 你可以将复杂构造代码从产品的业务逻辑中分离出来。

缺点:

  • 由于该模式需要新增多个类, 因此代码整体复杂程度会有所增加。

练手题目

题目描述

小明家新开了一家自行车工厂,用于使用自行车配件(车架 frame 和车轮 tires )进行组装定制不同的自行车,包括山地车和公路车。

山地车使用的是Aluminum Frame(铝制车架)和 Knobby Tires(可抓地轮胎),公路车使用的是 Carbon Frame (碳车架)和 Slim Tries。

现在它收到了一笔订单,要求定制一批自行车,请你使用【建造者模式】告诉小明这笔订单需要使用那些自行车配置吧。

输入描述

输入的第一行是一个整数 N(1 ≤ N ≤ 100),表示订单的数量。

接下来的 N 行,每行输入一个字符串,字符串表示客户的自行车需求。

字符串可以包含关键词 “mountain” 或 “road”,表示客户需要山地自行车或公路自行车。

输出描述

对于每笔订单,输出该订单定制的自行车配置。

在这里插入图片描述

提示信息

在本例中:产品为自行车,可以有两个建造者:山地车建造者和公路车建造者。

题解

使用模版方法模式和建造者模式实现自行车工厂。

import java.util.ArrayList;
import java.util.Scanner;

//抽象类,模版方法模式创建
abstract class Bicycle{
    private ArrayList<String> fittingsList = new ArrayList<String>();
    
    //选用不同配件的方法
    protected void useAluminumFrame(){};
    protected void useKnobbyTires(){};
    protected void useCarbonFrame(){};
    protected void useSlimTires(){};
    
    //设置配件列表
    public final void setFittingsList(ArrayList<String> list){
        this.fittingsList = list;
    }
    
    //选用配件,构建自行车
    public final void maker(){
			   for (String fitting : fittingsList) {
            switch (fitting) {
                case "useAluminumFrame":
                    useAluminumFrame();
                    break;
                case "useKnobbyTires":
                    useKnobbyTires();
                    break;
                case "useCarbonFrame":
                    useCarbonFrame();
                    break;
                case "useSlimTires":
                    useSlimTires();
                    break;
                default:
                    System.out.println("不清楚的配件:" + fitting + "请重新输入!");
            }
        }
    }
}

//山地自行车类,并重写父类方法
class MountainBicycle extends Bicycle{
    @Override
    protected void useAluminumFrame(){
        System.out.print("Aluminum Frame ");
    }
    @Override
    protected void useKnobbyTires(){
        System.out.println("Knobby Tires ");
    }
}

//公路自行车类,并重写父类方法
class RoadBicycle extends Bicycle{
    @Override
    protected void useCarbonFrame(){
        System.out.print("Carbon Frame ");
    }
    @Override
    protected void useSlimTires(){
        System.out.println("Slim Tires ");
    }
}

//定义建造者接口
interface Builder{
    void setFittingList(ArrayList<String> list);
    Bicycle getBicycle();
}

//山地自行车建造类
class MountainBicycleBuilder implements Builder{
    private MountainBicycle mountainBicycle = new MountainBicycle();
    
    public  void setFittingList(ArrayList<String> list){
        this.mountainBicycle.setFittingsList(list);
    }
    
    public  Bicycle getBicycle(){
        return this.mountainBicycle;
    }
}

//公路自行车建造者类
class RoadBicycleBuilder implements Builder{
    private RoadBicycle roadBicycle = new RoadBicycle();
    
    public  void setFittingList(ArrayList<String> list){
        this.roadBicycle.setFittingsList(list);
    }
    
    public  Bicycle getBicycle(){
        return this.roadBicycle;
    }
}

//导演类
class Director{
    private ArrayList<String> arrayList = new ArrayList<String>();
    private MountainBicycleBuilder mountainBicycleBuilder = new MountainBicycleBuilder();
    private RoadBicycleBuilder roadBicycleBuilder = new RoadBicycleBuilder();
    
    public MountainBicycle getMountainBicycle(){
		//清理场景
        this.arrayList.clear();
        //选用配件
        this.arrayList.add("useAluminumFrame");
        this.arrayList.add("useKnobbyTires");
        this.mountainBicycleBuilder.setFittingList(this.arrayList);
        return (MountainBicycle)this.mountainBicycleBuilder.getBicycle();
    }
    
    public RoadBicycle getRoadBicycle(){
		    //清理场景
        this.arrayList.clear();
        //选用配件
        this.arrayList.add("useCarbonFrame");
        this.arrayList.add("useSlimTires");
        this.roadBicycleBuilder.setFittingList(this.arrayList);
        return (RoadBicycle)this.roadBicycleBuilder.getBicycle();
    }
    
}

//主程序类
public class Main{
    public static void main (String[] args) {
        Scanner scanner = new Scanner(System.in);
        try {
            int num = scanner.nextInt();
            scanner.nextLine();
            Director director = new Director();

            for (int i = 0; i < num; i++) {
                String type = scanner.nextLine().toLowerCase().trim();
                Bicycle bicycle;
                if ("mountain".equals(type)) {
                    bicycle = director.getMountainBicycle();
                } else if ("road".equals(type)) {
                    bicycle = director.getRoadBicycle();
                } else {
                    System.out.println("无效输入. 请输入 'mountain' 或 'road'.");
                    continue;
                }
                bicycle.maker(); 
            }
        } catch (Exception e) {
            System.out.println("An error occurred: " + e.getMessage());
        } finally {
            scanner.close(); 
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UE5的引擎初始化流程

UE5的引擎初始化流程 首先跟着UE的官方文档[1]获取到UE的源代码&#xff0c;然后在参考GitHub上repo的readme&#xff0c;将UE引擎从源码build出来。以Windows平台为例&#xff0c;先找到引擎的入口函数&#xff1a; int32 WINAPI WinMain(_In_ HINSTANCE hInInstance, _In_op…

头歌资源库(17)多机调度问题

一、 问题描述 二、算法思想 首先&#xff0c;将作业按照所需时间从大到小排序。 创建一个长度为m的数组task_time&#xff0c;用来记录每台机器已经加工的作业时间。 从第一个作业开始&#xff0c;依次将作业分配给空闲的机器&#xff0c;并更新task_time数组。 对于每个…

springboot 集成阿里云 OSS

引入依赖 <!-- 阿里云oss依赖 --> <dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.9.1</version> </dependency><?xml version"1.0" encoding"…

阿里云centos 7.9 使用宝塔面板部署.netcore 6.0

前言&#xff1a; 我有一个netcore6.0的系统接口和手机端程序的站点程序之前是部署在一台windows测试服务器的IIS站点中&#xff0c; 服务器最近压力太大扛不住了&#xff0c;买了一台centos7.9的阿里云服务器准备进行迁移。具体操作日记如下。 一、安装宝塔面板 这一步涉及…

【人工智能学习之图像操作(二)】

【人工智能学习之图像操作&#xff08;二&#xff09;】 图像上的运算图像混合按位运算 图像的几何变换仿射变换透视变换膨胀操作腐蚀操作开操作闭操作梯度操作礼帽操作黑帽操作 图像上的运算 图像上的算术运算&#xff0c;加法&#xff0c;减法&#xff0c;图像混合等。 加减…

AI进阶指南第五课,大模型相关概念(知识库,微调)

虽然前面大概讲了一下大模型的一些基本概念&#xff0c;但是那些都比较偏向于大模型本身&#xff0c;但是我们使用的时候如果只靠大模型肯定是不行的。 就好比如果一个人只有一个脑子&#xff0c;其他什么部位也没有的话&#xff0c;那场面。&#xff08;感觉现在网上的AI图片…

泰迪智能科技实验室产品-云计算资源管理平台介绍

云计算资源管理平台是一款集群应用程序管理平台&#xff0c;以Docker、Kubernetes为核心引擎的容器化应用部署、运行环境&#xff0c;对数据中心的物理服务器、网络、存储、虚拟服务器等基础架构资源进行集中统一的管理、分配、监控等。平台旨在围绕行业应用逐步由“虚拟化”向…

llama-3 本地化部署实验

国产大模型的API 有限&#xff0c;编写langchain 应用问题很多。使用openai 总是遇到网络问题&#xff0c;尝试使用ollama在本地运行llama-3。结果异常简单。效果不错。llama-3 的推理能力感觉比openai 的GPT-3.5 好。 Ollama 下载 官网&#xff1a;https://ollama.com/downl…

计算机毕业设计hadoop+spark+hive知识图谱医生推荐系统 医生数据分析可视化大屏 医生爬虫 医疗可视化 医生大数据 机器学习 大数据毕业设计

测试过程及结果 本次对于医生推荐系统测试通过手动测试的方式共进行了两轮测试。 &#xff08;1&#xff09;第一轮测试中执行了个20个测试用例&#xff0c;通过16个&#xff0c;失败4个&#xff0c;其中属于严重缺陷的1个&#xff0c;属于一般缺陷的3个。 &#xff08;2&am…

llm学习2--使用embedding和数据处理

首先可以简单了解一下向量数据库相关知识&#xff1a; 向量数据库相关知识&#xff08;搬运学习&#xff0c;建议还是看原文&#xff0c;这个只是我自己的学习记录&#xff09;-CSDN博客 补充&#xff1a; 使用embedding API 文心千帆API Embedding-V1是基于百度文心大模型…

微服务应用与开发知识点练习【Gateway,OpenFeign,Dubbo,RocketMQ和RabbitMQ,JPA,Redis,Mycat】

一、选择题 【Gateway】 1.Spring Cloud Gateway与Nacos整合实现负载均衡时&#xff0c;路由配置中的URI前缀应该是&#xff1f;&#xff08;A &#xff09; A. lb:// B. nacos:// C. http:// D. discovery:// Spring Cloud Gateway与Nacos整合实现负载均衡时&#xff0c…

【Linux系统编程】进程控制(创建、退出、等待、替换)

目录 再聊进程创建 进程终止 进程等待 进程程序替换 再聊进程创建 初识进程创建 关于进程创建&#xff0c;这里只会说结论&#xff0c;在上面这篇文章中对进程创建进行了比较详细的阐述&#xff0c;而接下来要介绍的&#xff0c;都是基于上文说过的来展开的 一些较为重要…

【FFmpeg】avformat_alloc_output_context2函数

【FFmpeg】avformat_alloc_output_context2函数 1.avformat_alloc_output_context21.1 初始化AVFormatContext&#xff08;avformat_alloc_context&#xff09;1.2 格式猜测&#xff08;av_guess_format&#xff09;1.2.1 遍历可用的fmt&#xff08;av_muxer_iterate&#xff0…

Bad owner or permissions on C:\\Users\\username/.ssh/config > 过程试图写入的管道不存在。

使用windows连接远程服务器出现Bad owner or permissions 错误 问题&#xff1a; 需要修复文件权限 SSH 配置文件应具有受限权限以防止未经授权的访问 确保只有用户对该.ssh/config文件具有读取权限 解决方案&#xff1a; 在windows下打开命令行&#xff0c;通过以下命令打开文…

Spring Cloud Alibaba之负载均衡组件Ribbon

一、什么是负载均衡&#xff1f; &#xff08;1&#xff09;概念&#xff1a; 在基于微服务架构开发的系统里&#xff0c;为了能够提升系统应对高并发的能力&#xff0c;开发人员通常会把具有相同业务功能的模块同时部署到多台的服务器中&#xff0c;并把访问业务功能的请求均…

Kubernetes之 资源管理

系列文章目录 Kubernetes之 资源管理 文章目录 系列文章目录前言一、资源管理介绍二、YAML语言介绍 1.1.YAML语法&#xff1a;2.读入数据总结 一、资源管理介绍 在kubernetes中&#xff0c;所有的内容都抽象为资源&#xff0c;用户需要通过操作资源来管理kubernetes。 1. kub…

SMTP 转发器/中继

设置中继邮件服务器 我将设置一个邮件服务器&#xff0c;该服务器稍后将用作 SMTP 中继服务器。首先&#xff0c;在 Digital Ocean 中创建了一个新的 Ubuntu Droplet&#xff1a; Postfix MTA 安装在droplet上&#xff0c;并带有&#xff1a; apt-get install postfix 在pos…

序列检测器(Moore型)

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 参考代码 描述 请用Moore型状态机实现序列“1101”从左至右的不重叠检测。 电路的接口如下图所示。当检测到“1101”&#xff0c;Y输出一个时钟周期的高电平脉冲。 接口电路图如下&#xff1a; 输入描述&#xff1a…

【机器学习300问】132、自注意力机制(Self-Attention)和传统注意力机制(Attention)的区别?

最近学习注意力机制的时候&#xff0c;发现相同的概念很多&#xff0c;有必要给这些概念做一下区分&#xff0c;不然后续的学习可能会混成一团。本文先区分一下自注意力机制和传统注意力机制。我会先直接给出它们之间有何区别的结论&#xff0c;然后通过一个例子来说明。 【机…

阿里云服务器通过镜像下hunggingface上的模型

参考连接https://blog.csdn.net/lanlinjnc/article/details/136709225 https://www.bilibili.com/video/BV1VT421X7xe/?spm_id_from333.337.search-card.all.click&vd_source1ba257184239f03bd3caf4c6cab427e4 pip install -U huggingface_hub# 建议将上面这一行写入 ~/…