零基础设计模式——创建型模式 - 生成器模式
第二部分:创建型模式 - 生成器模式 (Builder Pattern)
前面我们学习了单例、工厂方法和抽象工厂模式,它们都关注如何创建对象。生成器模式(也常被称为建造者模式)是另一种创建型模式,它专注于将一个复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。
- 核心思想:将一个复杂对象的构建层与其表示层分离,使得同样的构建过程可以创建不同的表示。
生成器模式 (Builder Pattern)
“将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的对象表示。”
想象一下去快餐店点餐,比如赛百味 (Subway) 或者定制汉堡店:
- 复杂对象:你最终得到的定制三明治或汉堡。
- 构建过程:选择面包类型 -> 选择肉类 -> 选择蔬菜 -> 选择酱料 -> 完成。
- 表示:
- 三明治A:全麦面包 + 鸡肉 + 生菜番茄 + 蜂蜜芥末酱。
- 三明治B:白面包 + 牛肉 + 洋葱青椒 + 西南酱。
- 汉堡C:芝麻面包 + 双层牛肉饼 + 酸黄瓜 + 特制酱。
服务员(Director)会按照固定的步骤(选择面包、肉、菜、酱)来询问你。你(作为构建指令的提供者,或者说,你指导一个Builder)告诉服务员每一步你的选择。最终,服务员根据你的选择组装出你想要的三明治或汉堡。
这个模式的关键在于,构建过程(点餐步骤)是标准化的,但每一步的具体选择(面包种类、肉类种类等)是灵活的,从而可以产生多种不同的最终产品(表示)。
1. 目的 (Intent)
生成器模式的主要目的:
- 封装复杂对象的创建过程:当一个对象的创建过程非常复杂,包含多个步骤或多个部分时,使用生成器模式可以将这个复杂的构建逻辑封装起来。
- 分步构建对象:允许你分步骤、按顺序地构建一个对象,而不是一次性通过一个巨大的构造函数来创建。
- 创建不同表示:使得同样的构建过程可以创建出内部结构不同(即属性不同)的多种对象表示。
- 更好的控制构建过程:Director 控制构建的顺序和步骤,Builder 负责实现每个步骤。
2. 生活中的例子 (Real-world Analogy)
-
组装电脑:
- Product (产品):一台组装好的电脑。
- Builder (抽象建造者):
ComputerBuilder
接口,定义了安装CPU、主板、内存、硬盘、显卡等步骤的方法。 - ConcreteBuilder (具体建造者):
GamingComputerBuilder
(选择高性能CPU、高端显卡、大内存),OfficeComputerBuilder
(选择性价比CPU、集成显卡、普通内存)。 - Director (指挥者):电脑装机员。他按照固定的顺序(先装CPU到主板,再装内存条,再装入机箱…)来指导
Builder
进行组装。他不需要知道具体用的是什么牌子的CPU或显卡,这些由具体的Builder
决定。
客户只需要告诉装机员他想要一台“游戏电脑”还是“办公电脑”(选择了哪个ConcreteBuilder
),装机员就能按部就班地组装出来。
-
编写一份复杂的文档 (如简历、报告):
- Product:最终的文档。
- Builder:
DocumentBuilder
接口,定义了buildHeader()
,buildBodyParagraph(text)
,buildListItem(item)
,buildFooter()
等方法。 - ConcreteBuilder:
ResumeBuilder
(简历的页眉是个人信息,页脚是联系方式),ReportBuilder
(报告的页眉是标题和日期,页脚是页码)。 - Director:文档生成程序。它调用
Builder
的方法来按顺序构建文档的各个部分。
-
URL 构建:Java中的
UriComponentsBuilder
或类似工具,允许你分步设置 scheme, host, port, path, query parameters 等来构建一个URL。
3. 结构 (Structure)
生成器模式通常包含以下角色:
- Product (产品):表示被构建的复杂对象。ConcreteBuilder 创建该产品的内部表示并定义它的装配过程。
- Builder (抽象建造者):为创建一个 Product对象的各个部件指定抽象接口。它通常包含一系列
buildPartX()
方法和一个getResult()
方法用于返回构建好的产品。 - ConcreteBuilder (具体建造者):实现 Builder 接口,构造和装配产品的各个部件。定义并明确它所创建的表示,并提供一个检索产品的接口。
- Director (指挥者/导演):构造一个使用 Builder 接口的对象。Director 类负责调用具体建造者角色以创建产品对象。Director 并不保存对具体建造者角色的引用,而是通过其抽象接口与之协作。
构建流程:
- 客户端创建一个
ConcreteBuilder
对象。 - 客户端创建一个
Director
对象,并将ConcreteBuilder
对象传递给它。 Director
调用Builder
接口中定义的方法,按特定顺序指导ConcreteBuilder
构建产品。ConcreteBuilder
逐步构建产品的内部表示。- 客户端从
ConcreteBuilder
中获取构建完成的Product
。
4. 适用场景 (When to Use)
- 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
- 当构造过程必须允许被构造的对象有不同的表示时。
- 对象的构建过程非常复杂,包含多个可选步骤或配置。例如,创建一个复杂的配置对象,其中某些配置项是可选的,或者有多种组合方式。
- 需要分步创建一个对象,并且在每一步之后可能需要进行一些中间操作或验证。
- 希望隐藏对象的内部表示和构建细节。
- 一个对象有非常多的构造参数,其中大部分是可选的。如果用构造函数,可能会导致构造函数参数列表过长,或者需要多个重载的构造函数(伸缩构造函数问题)。生成器模式可以提供更优雅的链式调用方式。
5. 优缺点 (Pros and Cons)
优点:
- 封装性好:使得客户端不必知道产品内部组成的细节,产品本身和创建过程解耦。
- 易于控制构建过程:Director 可以精确控制构建的顺序和步骤。
- 可以创建不同表示:同样的构建过程可以应用于不同的 ConcreteBuilder,从而得到不同的产品表示。
- 更好的可读性和易用性:对于有很多可选参数的复杂对象,使用链式调用的生成器比使用长参数列表的构造函数更清晰。
- 分步构建:可以将产品的构建过程分解为多个独立的步骤,使得构建过程更加灵活。
缺点:
- 类的数量增多:需要为每个产品创建一个 ConcreteBuilder 类,如果产品种类很多,会导致类的数量增加。
- 产品必须有共同点:生成器模式创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用生成器模式。
- 模式本身相对复杂:相比于工厂模式,生成器模式的结构更复杂,包含的角色更多。
6. 实现方式 (Implementations)
让我们通过一个构建“报告文档”的例子来看看生成器模式的实现。报告可以有标题、作者、日期、多个段落内容、以及页脚。
Product (ReportDocument)
// report_document.go
package reportimport ("fmt""strings"
)// ReportDocument 产品
type ReportDocument struct {Title stringAuthor stringDate stringContents []stringFooter string
}func (rd *ReportDocument) AddContent(paragraph string) {rd.Contents = append(rd.Contents, paragraph)
}func (rd *ReportDocument) Display() {fmt.Println("========================================")if rd.Title != "" {fmt.Printf("Title: %s\n", rd.Title)}if rd.Author != "" {fmt.Printf("Author: %s\n", rd.Author)}if rd.Date != "" {fmt.Printf("Date: %s\n", rd.Date)}fmt.Println("----------------------------------------")for _, content := range rd.Contents {fmt.Println(content)}fmt.Println("----------------------------------------")if rd.Footer != "" {fmt.Printf("Footer: %s\n", rd.Footer)}fmt.Println("========================================")
}
// ReportDocument.java
package com.example.report;import java.util.ArrayList;
import java.util.List;// 产品
public class ReportDocument {private String title;private String author;private String date;private List<String> contents = new ArrayList<>();private String footer;public void setTitle(String title) { this.title = title; }public void setAuthor(String author) { this.author = author; }public void setDate(String date) { this.date = date; }public void addContent(String paragraph) { this.contents.add(paragraph); }public void setFooter(String footer) { this.footer = footer; }public void display() {System.out.println("========================================");if (title != null && !title.isEmpty()) {System.out.println("Title: " + title);}if (author != null && !author.isEmpty()) {System.out.println("Author: " + author);}if (date != null && !date.isEmpty()) {System.out.println("Date: " + date);}System.out.println("----------------------------------------");for (String content : contents) {System.out.println(content);}System.out.println("----------------------------------------");if (footer != null && !footer.isEmpty()) {System.out.println("Footer: " + footer);}System.out.println("========================================");}
}
Builder (ReportBuilder)
// report_builder.go
package report// ReportBuilder 抽象建造者接口
type ReportBuilder interface {SetTitle(title string)SetAuthor(author string)SetDate(date string)AddParagraph(paragraph string)SetFooter(footer string)GetReport() *ReportDocument
}
// ReportBuilder.java
package com.example.report;// 抽象建造者接口
public interface ReportBuilder {void setTitle(String title);void setAuthor(String author);void setDate(String date);void addParagraph(String paragraph);void setFooter(String footer);ReportDocument getReport();
}
ConcreteBuilder (SimpleReportBuilder, DetailedReportBuilder)
// simple_report_builder.go
package report// SimpleReportBuilder 具体建造者 - 构建简单报告
type SimpleReportBuilder struct {document *ReportDocument
}func NewSimpleReportBuilder() *SimpleReportBuilder {return &SimpleReportBuilder{document: &ReportDocument{}}
}func (b *SimpleReportBuilder) SetTitle(title string) { b.document.Title = "Simple Report: " + title }
func (b *SimpleReportBuilder) SetAuthor(author string) { /* 简单报告不包含作者 */ }
func (b *SimpleReportBuilder) SetDate(date string) { b.document.Date = date }
func (b *SimpleReportBuilder) AddParagraph(paragraph string) { b.document.AddContent(paragraph) }
func (b *SimpleReportBuilder) SetFooter(footer string) { b.document.Footer = "End of Simple Report." }
func (b *SimpleReportBuilder) GetReport() *ReportDocument { return b.document }// detailed_report_builder.go
package report// DetailedReportBuilder 具体建造者 - 构建详细报告
type DetailedReportBuilder struct {document *ReportDocument
}func NewDetailedReportBuilder() *DetailedReportBuilder {return &DetailedReportBuilder{document: &ReportDocument{}}
}func (b *DetailedReportBuilder) SetTitle(title string) { b.document.Title = "Detailed Analysis: " + title }
func (b *DetailedReportBuilder) SetAuthor(author string) { b.document.Author = author }
func (b *DetailedReportBuilder) SetDate(date string) { b.document.Date = "Generated on: " + date }
func (b *DetailedReportBuilder) AddParagraph(paragraph string) { b.document.AddContent("\t- " + paragraph) }
func (b *DetailedReportBuilder) SetFooter(footer string) { b.document.Footer = fmt.Sprintf("Report Concluded. %s. (c) MyCompany", footer)
}
func (b *DetailedReportBuilder) GetReport() *ReportDocument { return b.document }
// SimpleReportBuilder.java
package com.example.report;// 具体建造者 - 构建简单报告
public class SimpleReportBuilder implements ReportBuilder {private ReportDocument document;public SimpleReportBuilder() {this.document = new ReportDocument();System.out.println("SimpleReportBuilder: Initialized.");}@Overridepublic void setTitle(String title) {document.setTitle("Simple Report: " + title);}@Overridepublic void setAuthor(String author) {// 简单报告不包含作者System.out.println("SimpleReportBuilder: Author field is ignored for simple reports.");}@Overridepublic void setDate(String date) {document.setDate(date);}@Overridepublic void addParagraph(String paragraph) {document.addContent(paragraph);}@Overridepublic void setFooter(String footer) {document.setFooter("End of Simple Report.");}@Overridepublic ReportDocument getReport() {return document;}
}// DetailedReportBuilder.java
package com.example.report;// 具体建造者 - 构建详细报告
public class DetailedReportBuilder implements ReportBuilder {private ReportDocument document;public DetailedReportBuilder() {this.document = new ReportDocument();System.out.println("DetailedReportBuilder: Initialized.");}@Overridepublic void setTitle(String title) {document.setTitle("Detailed Analysis: " + title);}@Overridepublic void setAuthor(String author) {document.setAuthor(author);}@Overridepublic void setDate(String date) {document.setDate("Generated on: " + date);}@Overridepublic void addParagraph(String paragraph) {document.addContent("\t- " + paragraph); // 添加缩进和项目符号}@Overridepublic void setFooter(String footer) {document.setFooter(String.format("Report Concluded. %s. (c) MyCompany", footer));}@Overridepublic ReportDocument getReport() {return document;}
}
Director (ReportDirector)
// report_director.go
package report// ReportDirector 指挥者
type ReportDirector struct {builder ReportBuilder
}func NewReportDirector(builder ReportBuilder) *ReportDirector {return &ReportDirector{builder: builder}
}// ConstructMonthlyReport 指挥构建月度报告
func (d *ReportDirector) ConstructMonthlyReport(title, author, date string, contents []string, footerDetails string) *ReportDocument {d.builder.SetTitle(title)d.builder.SetAuthor(author) // Builder 内部可能忽略此项d.builder.SetDate(date)for _, p := range contents {d.builder.AddParagraph(p)}d.builder.SetFooter(footerDetails)return d.builder.GetReport()
}// ConstructQuickSummary 指挥构建快速摘要
func (d *ReportDirector) ConstructQuickSummary(title, date string, summaryContent string) *ReportDocument {d.builder.SetTitle(title)// 快速摘要可能不需要作者和完整页脚d.builder.SetDate(date)d.builder.AddParagraph(summaryContent)d.builder.SetFooter("Quick Summary") // 简化页脚return d.builder.GetReport()
}
// ReportDirector.java
package com.example.report;import java.util.List;// 指挥者
public class ReportDirector {private ReportBuilder builder;public ReportDirector(ReportBuilder builder) {this.builder = builder;System.out.println("ReportDirector: Configured with builder: " + builder.getClass().getSimpleName());}// 指挥构建月度报告public ReportDocument constructMonthlyReport(String title, String author, String date, List<String> contents, String footerDetails) {System.out.println("ReportDirector: Constructing Monthly Report...");builder.setTitle(title);builder.setAuthor(author); // Builder 内部可能忽略此项builder.setDate(date);for (String p : contents) {builder.addParagraph(p);}builder.setFooter(footerDetails);return builder.getReport();}// 指挥构建快速摘要public ReportDocument constructQuickSummary(String title, String date, String summaryContent) {System.out.println("ReportDirector: Constructing Quick Summary...");builder.setTitle(title);// 快速摘要可能不需要作者和完整页脚builder.setDate(date);builder.addParagraph(summaryContent);builder.setFooter("Quick Summary"); // 简化页脚return builder.getReport();}
}
客户端使用
// main.go (示例用法)
/*
package mainimport ("./report""time"
)func main() {// 构建简单月度报告simpleBuilder := report.NewSimpleReportBuilder()director1 := report.NewReportDirector(simpleBuilder)monthlyContents := []string{"Sales are up by 10%.","Customer satisfaction is high.",}simpleMonthlyReport := director1.ConstructMonthlyReport("October Sales","Sales Team", // SimpleBuilder 会忽略作者time.Now().Format("2006-01-02"),monthlyContents,"Internal Use Only",)simpleMonthlyReport.Display()fmt.Println("\n-----------------------------------\n")// 构建详细年度报告detailedBuilder := report.NewDetailedReportBuilder()director2 := report.NewReportDirector(detailedBuilder)annualContents := []string{"Market share increased by 5%.","New product line launched successfully with positive feedback.","Research and Development made significant progress on Project X.",}detailedAnnualReport := director2.ConstructMonthlyReport( // 复用构建逻辑,但用不同的builder"Annual Financials 2023","Dr. Alice Smith, CFO",time.Now().Format("Jan 02, 2006"),annualContents,"For Shareholders",)detailedAnnualReport.Display()fmt.Println("\n-----------------------------------\n")// 使用同一个 detailedBuilder 构建另一种类型的报告 (快速摘要)quickSummary := director2.ConstructQuickSummary("Q3 Highlights",time.Now().Format("2006-01-02"),"Overall positive quarter with key targets met.",)quickSummary.Display()
}
*/
// Main.java (示例用法)
/*
package com.example;import com.example.report.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;public class Main {public static void main(String[] args) {String currentDate = LocalDate.now().format(DateTimeFormatter.ISO_DATE);// 构建简单月度报告System.out.println("--- Building Simple Monthly Report ---");ReportBuilder simpleBuilder = new SimpleReportBuilder();ReportDirector director1 = new ReportDirector(simpleBuilder);List<String> monthlyContents = Arrays.asList("Sales are up by 10%.","Customer satisfaction is high.");ReportDocument simpleMonthlyReport = director1.constructMonthlyReport("October Sales","Sales Team", // SimpleBuilder 会忽略作者currentDate,monthlyContents,"Internal Use Only");simpleMonthlyReport.display();System.out.println("\n--- Building Detailed Annual Report ---");// 构建详细年度报告ReportBuilder detailedBuilder = new DetailedReportBuilder();ReportDirector director2 = new ReportDirector(detailedBuilder);List<String> annualContents = Arrays.asList("Market share increased by 5%.","New product line launched successfully with positive feedback.","Research and Development made significant progress on Project X.");ReportDocument detailedAnnualReport = director2.constructMonthlyReport( // 复用构建逻辑,但用不同的builder"Annual Financials 2023","Dr. Alice Smith, CFO",LocalDate.now().format(DateTimeFormatter.ofPattern("MMM dd, yyyy")),annualContents,"For Shareholders");detailedAnnualReport.display();System.out.println("\n--- Building Quick Summary with Detailed Builder ---");// 使用同一个 detailedBuilder 构建另一种类型的报告 (快速摘要)ReportDocument quickSummary = director2.constructQuickSummary("Q3 Highlights",currentDate,"Overall positive quarter with key targets met.");quickSummary.display();}
}
*/
关于链式调用 (Fluent Interface)
在很多现代语言的实现中,Builder
的 buildPartX()
方法通常会返回 this
(或 self
),以支持链式调用,这样客户端代码可以更简洁。这种情况下,Director
角色有时会被弱化,甚至省略,客户端直接通过链式调用来指导 Builder
。
Java 链式调用示例 (不使用显式 Director):
// MailMessage.java (Product)
package com.example.mail;public class MailMessage {private String from;private String to;private String subject;private String body;private String cc;// 私有构造,强制使用Builderprivate MailMessage(Builder builder) {this.from = builder.from;this.to = builder.to;this.subject = builder.subject;this.body = builder.body;this.cc = builder.cc;}@Overridepublic String toString() {return "MailMessage{" +"from='" + from + '\'' +", to='" + to + '\'' +", subject='" + subject + '\'' +", body='" + body + '\'' +(cc != null ? ", cc='" + cc + '\'' : "") +'}';}// 静态内部 Builder 类public static class Builder {private String from;private String to; // 必填private String subject;private String body;private String cc; // 可选public Builder(String to) { // 必填项通过构造函数传入this.to = to;}public Builder from(String from) {this.from = from;return this;}public Builder subject(String subject) {this.subject = subject;return this;}public Builder body(String body) {this.body = body;return this;}public Builder cc(String cc) {this.cc = cc;return this;}public MailMessage build() {if (this.from == null || this.from.isEmpty()) {throw new IllegalStateException("From address cannot be empty");}// 可以在这里添加更多校验逻辑return new MailMessage(this);}}
}// Main.java (示例用法)
/*
package com.example;import com.example.mail.MailMessage;public class Main {public static void main(String[] args) {MailMessage message1 = new MailMessage.Builder("recipient@example.com").from("sender@example.com").subject("Hello from Builder Pattern!").body("This is a demonstration of the fluent builder pattern.").cc("manager@example.com").build();System.out.println(message1);MailMessage message2 = new MailMessage.Builder("another@example.com").from("noreply@example.com").subject("Important Update")// body 和 cc 是可选的.build();System.out.println(message2);try {MailMessage message3 = new MailMessage.Builder("test@example.com")// .from("testsender@example.com") // 故意不设置 from.subject("Test").build();System.out.println(message3);} catch (IllegalStateException e) {System.err.println("Error building message: " + e.getMessage());}}
}
*/
这种链式调用的方式在Java中非常流行,例如 StringBuilder
, OkHttp Request.Builder
, Lombok @Builder
注解等。
7. 与抽象工厂模式的区别
-
抽象工厂模式 (Abstract Factory):
- 关注点:创建产品族 (一系列相关的产品对象)。
- 产品创建:通常是一次性获取整个产品族中的某个产品 (例如
factory.createButton()
)。 - 目的:保证创建出来的产品属于同一个系列,相互兼容。
-
生成器模式 (Builder):
- 关注点:创建单个复杂对象,其构建过程包含多个步骤。
- 产品创建:分步骤构建,最后通过
getResult()
或build()
获取完整对象。 - 目的:将复杂对象的构建过程和其表示分离,允许同样的构建过程创建不同的表示。
关键区别:
- 抽象工厂返回的是多个不同类型的产品(但它们属于一个系列)。
- 生成器返回的是一个复杂的产品,这个产品是逐步构建起来的。
- 抽象工厂通常在客户端决定使用哪个具体工厂后,由工厂直接创建出产品。而生成器模式中,Director 控制构建步骤,Builder 实现这些步骤。
有时,生成器模式的 buildPartX()
方法内部可能会使用工厂方法来创建部件。
8. 总结
生成器模式是一种强大的创建型模式,适用于构建具有多个组成部分、构建过程复杂或需要多种表示的复杂对象。它通过将构建过程与对象的表示分离,提高了代码的模块化程度和灵活性。当遇到有很多可选参数的构造函数时,或者当对象的创建逻辑比较复杂时,可以考虑使用生成器模式来简化对象的创建和提高代码的可读性。
记住它的核心:分步构建复杂对象,不同表示。
相关文章:

零基础设计模式——创建型模式 - 生成器模式
第二部分:创建型模式 - 生成器模式 (Builder Pattern) 前面我们学习了单例、工厂方法和抽象工厂模式,它们都关注如何创建对象。生成器模式(也常被称为建造者模式)是另一种创建型模式,它专注于将一个复杂对象的构建过程…...

MD编辑器推荐【Obsidian】含下载安装和实用教程
为什么推荐 Obsidian ? 免费 (Typora 开始收费了)Typora 实现的功能,它都有!代码块可一键复制 文件目录支持文件夹 大纲支持折叠、搜索 特色功能 – 白板 特色功能 – 关系图谱 下载 https://pan.baidu.com/s/1I1fSly…...
LLama-Factory 遇到的问题
目录 一、LLama-Factory安装 二、LLama-Factory 遇到的问题 (一)包不兼容问题 (二)使用文件路径,加载模型 一、LLama-Factory安装 参考官网介绍:https://github.com/hiyouga/LLaMA-Factory 二、LLama…...
I-CON: A UNIFYING FRAMEWORK FOR REPRESENTATION LEARNING
I-con:表示学习的统一框架 基本信息 ICLR 2025 博客贡献人 田心 作者 Shaden Alshammari, John Hershey, Axel Feldmann, William T. Freeman, Mark Hamilton 关键词 I-Con框架,表征学习,损失函数统一框架 摘要 随着表征学习领域的快速发展,各类…...

Missashe线代题型总结
Missashe线性代数考研题型总结 说明:这篇笔记用于博主对"线代"常考题型进行总结,99%为真题,大概可能应该会逐步更新解题思路。有目录可直接检索。 第一章 行列式 1 具体行列式计算 1)么字型 2015 数一 2016 数一三…...
蓝桥杯13届 卡牌
问题描述 这天, 小明在整理他的卡牌。 他一共有 n 种卡牌, 第 i 种卡牌上印有正整数数 i(i∈[1,n]), 且第 i 种卡牌 现有 ai 张。 而如果有 n 张卡牌, 其中每种卡牌各一张, 那么这 n 张卡牌可以被称为一 套牌。小明为了凑出尽可能多套牌, 拿出了 m 张空白牌, 他可以在上面…...

安卓开发用到的设计模式(1)创建型模式
安卓开发用到的设计模式(1)创建型模式 文章目录 安卓开发用到的设计模式(1)创建型模式1. 单例模式(Singleton Pattern)2. 工厂模式(Factory Pattern)3. 抽象工厂模式(Abs…...
【PalladiumZ2 使用专栏 3 -- 信号值的获取与设置 及 memory dump 与 memory load】
文章目录 Overviewforce 命令语法value 命令语法memory loadmemory dump Overview 在调试问题的时,有时需要将某些信号强制设置为某个值,或者某几个信号强制设置为某个值,这里就要用到 force 命令。 force 命令语法 force -h force <na…...
flutter dart 函数语法
以下是 Dart 语言中函数语法的 详细实例说明,涵盖了所有常用写法 基本语法参数类型(必选、可选、命名、默认值)匿名函数、箭头函数高阶函数(函数作为参数/返回值)异步函数(async / await) 1. …...
课外活动:大语言模型Claude的技术解析 与 自动化测试框架领域应用实践
大语言模型Claude的技术解析与测试领域应用实践 一、Claude模型的核心优势解析 1.1 关键技术特性对比 维度Claude 3 OpusGPT-4 Turbo核心优势上下文窗口200K tokens128K tokens长文档处理能力提升56%逻辑推理准确率92.3% (GSM8K数据集)89.7%复杂场景稳定性更强代码生成速度7…...

线程的一些基本知识
前言 最近在学习线程,线程与进程是面试中可能常考的问题,我总结了线程的一些知识。分享给大家,希望可以帮组到大家。 线程知识总结(包含与进程的区别) 结语 希望可以帮助到有需要的人,bye~~...

【Python打卡Day30】模块与包的导入@浙大疏锦行
#一、导入官方库 我们复盘下学习python的逻辑,所谓学习python就是学习python常见的基础语法学习你所处理任务需要用到的第三方库 所以你用到什么学什么库即可。学习python本身就是个伪命题,就像你说学习科目一样,你没说清晰你学习的具体科目…...

26考研|高等代数:λ-矩阵
前言 本章知识点较为简单,是作为工具性的一章,在学习过程中,要注意区分行列式因子、不变因子以及初等因子,同时还要对若尔当标准型的计算应该足够熟悉,尤其是复矩阵的若尔当标准型计算是十分重要的。 课本重点回顾 …...

我店模式系统开发打造本地生活生态商圈
在当今快节奏的商业环境中,商家们面临着越来越多的挑战,包括市场竞争加剧、消费者需求多样化以及运营效率的提高等。为了应对这些挑战,越来越多的商家开始寻求信息化解决方案,以提升运营效率和客户体验。我的店模式系统平台应运而…...

数据库练习(3)
简单选择题要点: 1.锁协议: 数据库原理及应用(高级篇)01——封锁协议(图文并解,超详细,一看就会)_数据库锁协议-CSDN博客https://blog.csdn.net/qq_44236958/article/details/105790970 2.tablespace和datafile 一个tablespace可以有一个或多…...

OpenGL ES 基本基本使用、绘制基本2D图形
OpenGL ES 绘制基础图形 OpenGL ES基本概念 OpenGL ES (Embedded-System) 是专为嵌入式设备(如手机、平板、VR 设备)设计的图形 API,是 OpenGL 的轻量级版本。 |下面是一个Android使用 OpenGL ES的基本框架 MainActivity 设置一…...
spark调度系统核心组件SparkContext、DAGSchedul、TaskScheduler、Taskset介绍
目录 1. SparkContext2.DAGScheduler3. TaskScheduler4. 协作关系5 TaskSet的定义6. 组件关系说明Spark调度系统的核心组件主要有SparkContext、DAGScheduler和TaskScheduler SparkContext介绍 1. SparkContext 1、资源申请: SparkContext是Spark应用程序与集群管理器(如St…...

BU9792驱动段式LCD
1、C文件,需要自己添加软件iic或硬件iic驱动,该驱动在我的别的文章内有。亲测bu9792是正常驱动的(只用到了前14个SEG),说实话有点懵了。后面的ICSET有个P2根据不同的SEG地址要置1或0,读的时候最高位也是0?读命令寄存器…...
Springboot通过SSE实现实时消息返回
Server-Sent Events(SSE)是一种从服务器向客户端推送实时消息的技术。相较于WebSocket,SSE更为简单,适用于大多数实时消息场景。本文将深入探讨如何使用Spring Boot通过SSE实现实时消息返回。 一、什么是SSE SSE是一种允许服务器…...
SD-WAN技术详解:如何优化网络性能与QoS实现?(附QoS策略、链路聚合、网络架构对比)
随着企业数字化转型的快速推进,传统WAN架构逐渐难以满足企业在性能、成本和服务质量(QoS)方面的要求。尤其是企业关键业务应用(例如语音通话、高清视频会议、企业核心业务系统)对网络性能的要求越来越高。SD-WAN&#…...

力扣-将x减到0的最小操作数
1.题目描述 2.题目链接 1658. 将 x 减到 0 的最小操作数 - 力扣(LeetCode) 3.题目分析 1)正面求解困难 题目要求我们每次都从最左边或者最右边取一个数,使x-元素的值,并在数组中移除该元素。最后返回的最小操作数…...
Web前端开发: 什么是JavaScript?
什么是JavaScript? JavaScript 是一种广泛应用于网页开发的脚本语言,主要用于为网站添加交互性和动态功能。 1. 核心作用 前端开发:控制网页行为,例如点击按钮弹出提示、表单验证、动态加载内容等。 后端开发:通过 No…...

三、【数据建模篇】:用 Django Models 构建测试平台核心数据
【数据建模篇】:用 Django Models 构建测试平台核心数据 前言我们要设计哪些核心数据?准备工作:创建 Django App开始设计数据模型 (Models)1. 通用基础模型 (可选但推荐)2. 项目模型 (Project)3. 模块模型 (Module)4. 测试用例模型 (TestCase…...
【JAVA】比较器Comparator与自然排序(28)
JAVA 核心知识点详细解释 Java中比较器Comparator的概念和使用方法 概念 Comparator 是 Java 中的一个函数式接口,位于 java.util 包下。它用于定义对象之间的比较规则,允许我们根据自定义的逻辑对对象进行排序。与对象的自然排序(实现 Comparable 接口)不同,Comparat…...

shp2pgsql 导入 Shp 到 PostGIS 空间数据库
前言 ❝ shp2pgsql是PostGIS自带的命令行工具,用于将Shapefile文件声称SQL脚本导入到PostGIS空间数据库。 1. 安装 PostGIS 通过Application Stack Builder或者下载单独的PostGIS包进行安装。而shp2pgsql则是与PostGIS工具集成在一起,无需单独下载。该命…...

word设置如“第xx页 共xx页”格式的页码
问题1: 为word文档设置如“第xx页 共xx页”格式的页码。 解决方法: 1、鼠标双击页脚位置进入页脚编辑模式; 2、在页脚处输入“第 页 共 页”内容并居中; 3、将光标放在“第 页”之间并插入“Page”,执行操作“…...

DL00912-基于自监督深度聚类的高光谱目标检测含数据集
在科研的道路上,数据的获取与分析无疑是成功的关键。对于从事高光谱数据研究的你,我们为您带来了一款革命性的工具——基于自监督深度聚类的高光谱目标检测系统。 完整代码数据集见文末 这款系统通过最先进的自监督学习技术,结合深度聚类算…...
PostgreSQL架构
目录 一、PostgreSQL核心特性与优势 1.PostgreSQL简介 2.PostgreSQL的核心特点 (1)开源与自由 (2)高度符合SQL标准 (3)丰富的数据类型 (4)事务与并发控制 (5&…...
文章记单词 | 第111篇(六级)
一,单词释义 damage /ˈdmɪdʒ/ v./n. 损害;损坏;损失harbour /ˈhɑːbə(r)/ n. 港口;港湾 v. 庇护;窝藏(美式拼写:harbor)gasp /ɡsp/ v. 喘气;喘息 n. 喘息&#x…...
在Java中,将Object对象转换为具体实体类对象
在Java中,将Object对象转换为具体实体类对象可以通过以下几种方法实现: 1.使用instanceof关键字进行类型检查和转换: 首先,使用instanceof关键字检查Object对象是否为目标实体类的类型。 如果是,则进行强制类型…...