您在开发过程中是否遇到过需要处理复杂对象的情况?可能是因为它们要么参数太多,甚至可以嵌套,要么需要很多构建步骤和复杂的逻辑来构建。
也许您想设计一个具有简洁界面的模块,而不必每次都分散或思考复杂对象的创建代码!
这就是构建器设计模式的用武之地!
在本教程中,我们将解释有关构建器设计模式的所有内容,然后我们将构建一个 CLI Node.js 应用程序,用于使用 构建器设计模式 生成 DALL-E 3 优化的图像生成提示.
最终代码可在此 Github 存储库中获取。
Builder 是一种 创造设计模式,它是一类设计模式,用于处理使用 new 创建对象的本机方式所带来的不同问题。 关键字或运算符。
构建器设计模式专注于解决以下问题:
提供一个简单的接口来创建复杂的对象:想象一个深度嵌套的对象,它具有许多必需的初始化步骤。
将构造代码与对象本身分开,允许从同一对象创建多个表示或配置。
Builder 设计模式 通过将对象创建的责任委托给称为 builders 的特殊对象来解决这两个问题。
构建器对象组合原始对象,并将创建过程分解为多个阶段或步骤。
每个步骤都由构建器对象中的一个方法定义,该方法根据某些业务逻辑初始化对象属性的子集。
class PromptBuilder { private prompt: Prompt constructor() { this.reset() } reset() { this.prompt = new Prompt() } buildStep1() { this.prompt.subject = "A cheese eating a burger" //initialization code... return this } buildStep2() { //initialization code... return this } buildStep3() { //initialization code... return this } build() { const result = structuredClone(this.prompt) // deep clone this.reset() return result } }
客户端代码:我们只需要使用构建器并调用各个步骤
const promptBuilder = new PromptBuilder() const prompt1 = promptBuilder .buildStep1() // optional .buildStep2() // optional .buildStep3() // optional .build() // we've got a prompt const prompt2 = promptBuilder .buildStep1() // optional .buildStep3() // optional .build() // we've got a prompt
典型的构建器设计模式由 4 个主要类组成:
Builder :构建器接口应该只定义构造方法,而没有 build() 方法,该方法负责返回创建的实体。
具体构建器类:每个具体构建器都提供自己的构建器接口方法的实现,以便它可以生成自己的对象变体(产品1或产品2)。
客户端 :您可以将客户端视为我们对象的顶级消费者、导入库模块的用户或我们应用程序的入口点。
Director:即使同一个构建器对象也可以产生该对象的许多变体。
class PromptBuilder { private prompt: Prompt constructor() { this.reset() } reset() { this.prompt = new Prompt() } buildStep1() { this.prompt.subject = "A cheese eating a burger" //initialization code... return this } buildStep2() { //initialization code... return this } buildStep3() { //initialization code... return this } build() { const result = structuredClone(this.prompt) // deep clone this.reset() return result } }从上面的代码中可以看出,某些实体非常需要负责指导或编排对构建器方法的不同可能的调用组合序列,因为每个序列可能会产生不同的结果对象。
那么我们能否进一步抽象流程,为客户端代码提供更简单的接口?
这就是
Director 类 的用武之地。director 从客户端承担更多责任,并允许我们分解所有这些构建器序列调用并根据需要重用它们。
const promptBuilder = new PromptBuilder() const prompt1 = promptBuilder .buildStep1() // optional .buildStep2() // optional .buildStep3() // optional .build() // we've got a prompt const prompt2 = promptBuilder .buildStep1() // optional .buildStep3() // optional .build() // we've got a prompt
客户端代码
const promptBuilder = new PromptBuilder() const prompt1 = promptBuilder.buildStep1().buildStep2().build() const prompt2 = promptBuilder.buildStep1().buildStep3().build()从上面的代码可以看出,客户端代码不需要知道创建prompt1或prompt2的详细信息。它只是调用主管,设置正确的构建器对象,然后调用 makePrompt 方法。
实际场景
快速工程图像生成AI CLI工具。
此 CLI 应用程序的源代码可在此处获取。CLI 工具的工作方式如下:
文件:promps.ts
class Director { private builder: PromptBuilder constructor() {} setBuilder(builder: PromptBuilder) { this.builder = builder } makePrompt1() { return this.builder.buildStep1().buildStep2().build() } makePrompt2() { return this.builder.buildStep1().buildStep3().build() } }
文件:promps.ts
const director = new Director() const builder = new PromptBuilder() director.setBuilder(builder) const prompt1 = director.makePrompt1() const prompt2 = director.makePrompt2()如您所见,每种提示类型都需要构建许多复杂的属性,例如
artStyle 、 colorPalette 、 lightingEffect 、 perspective , 相机类型 ,等等
随意探索所有属性详细信息,这些详细信息在我们项目的enums.ts 文件中定义。
枚举.ts
class PromptBuilder { private prompt: Prompt constructor() { this.reset() } reset() { this.prompt = new Prompt() } buildStep1() { this.prompt.subject = "A cheese eating a burger" //initialization code... return this } buildStep2() { //initialization code... return this } buildStep3() { //initialization code... return this } build() { const result = structuredClone(this.prompt) // deep clone this.reset() return result } }
我们的 CLI 应用程序的用户可能不知道所有这些配置;他们可能只想根据特定的主题生成图像,例如吃奶酪汉堡和风格(现实或数字艺术)。
克隆 Github 存储库后,使用以下命令安装依赖项:
const promptBuilder = new PromptBuilder() const prompt1 = promptBuilder .buildStep1() // optional .buildStep2() // optional .buildStep3() // optional .build() // we've got a prompt const prompt2 = promptBuilder .buildStep1() // optional .buildStep3() // optional .build() // we've got a prompt
安装依赖项后,运行以下命令:
const promptBuilder = new PromptBuilder() const prompt1 = promptBuilder.buildStep1().buildStep2().build() const prompt2 = promptBuilder.buildStep1().buildStep3().build()
系统将提示您选择提示类型:现实或数字艺术。
然后您必须输入提示的主题。让我们坚持芝士汉堡。
根据您的选择,您将收到以下文字提示:
写实风格提示 :
class Director { private builder: PromptBuilder constructor() {} setBuilder(builder: PromptBuilder) { this.builder = builder } makePrompt1() { return this.builder.buildStep1().buildStep2().build() } makePrompt2() { return this.builder.buildStep1().buildStep3().build() } }
数字艺术风格提示 :
const director = new Director() const builder = new PromptBuilder() director.setBuilder(builder) const prompt1 = director.makePrompt1() const prompt2 = director.makePrompt2()
复制之前的命令,然后将其粘贴到 ChatGPT 中。 ChatGPT 将使用 DALL-E 3 模型来生成图像。
真实图像提示结果
数字艺术图像提示结果
记住提示参数的复杂性以及构建每种类型的提示所需的专业知识,更不用说所需的丑陋的构造函数调用。
class RealisticPhotoPrompt { constructor( public subject: string, public location: string, public timeOfDay: string, public weather: string, public camera: CameraType, public lens: LensType, public focalLength: number, public aperture: string, public iso: number, public shutterSpeed: string, public lighting: LightingCondition, public composition: CompositionRule, public perspective: string, public foregroundElements: string[], public backgroundElements: string[], public colorScheme: ColorScheme, public resolution: ImageResolution, public postProcessing: string[] ) {} }
免责声明:这种丑陋的构造函数调用在 JavaScript 中并不是一个大问题,因为我们可以传递一个所有属性都可为空的配置对象。
抽象构建提示的过程,并使我们的代码开放扩展并关闭修改(O in SOLID),并让我们的图书馆客户无缝或更轻松地使用我们的提示生成库,我们将选择实施构建器设计模式。
让我们首先声明通用提示生成器接口。
接口声明了一堆方法:
builders.ts
class PromptBuilder { private prompt: Prompt constructor() { this.reset() } reset() { this.prompt = new Prompt() } buildStep1() { this.prompt.subject = "A cheese eating a burger" //initialization code... return this } buildStep2() { //initialization code... return this } buildStep3() { //initialization code... return this } build() { const result = structuredClone(this.prompt) // deep clone this.reset() return result } }
builders.ts
const promptBuilder = new PromptBuilder() const prompt1 = promptBuilder .buildStep1() // optional .buildStep2() // optional .buildStep3() // optional .build() // we've got a prompt const prompt2 = promptBuilder .buildStep1() // optional .buildStep3() // optional .build() // we've got a prompt
从上面的实现中可以看到,每个构建器都选择构建自己类型的提示(最终的提示形状不同),同时坚持 PromptBuilder 合约定义的相同构建步骤!
现在,让我们继续我们的 Director 类定义。
导演.ts
const promptBuilder = new PromptBuilder() const prompt1 = promptBuilder.buildStep1().buildStep2().build() const prompt2 = promptBuilder.buildStep1().buildStep3().build()
Director 类包装了 PromptBuilder 并允许我们创建一个提示配置,其中包括调用从 setSubject 到 的所有构建器方法buildArtisticElements.
这将简化 index.ts 文件中的客户端代码,我们将在下一节中看到。
序列化器.ts
class Director { private builder: PromptBuilder constructor() {} setBuilder(builder: PromptBuilder) { this.builder = builder } makePrompt1() { return this.builder.buildStep1().buildStep2().build() } makePrompt2() { return this.builder.buildStep1().buildStep3().build() } }
为了将最终提示文本打印到终端控制台,我实现了一些实用程序序列化函数。
现在我们的提示库生成代码已经准备好了。让我们在 index.ts 文件中使用它。
index.ts
const director = new Director() const builder = new PromptBuilder() director.setBuilder(builder) const prompt1 = director.makePrompt1() const prompt2 = director.makePrompt2()
上面的代码执行以下操作:
请记住:不可能从导演那里获得提示,因为每种构建器类型产生的提示形状不同。结论
简化对象创建:该模式允许我们创建复杂的 RealisticPhotoPrompt 和 DigitalArtPrompt 对象,而无需将其复杂的构造过程暴露给客户端代码。
灵活性:通过为每种提示类型使用单独的构建器类,我们可以轻松添加新的提示类型或修改现有的提示类型,而无需更改客户端代码。
代码组织:该模式有助于将构造逻辑与表示分离,使代码更加模块化且更易于维护。
可重用性:PromptDirector 类允许我们为不同类型的提示重用相同的构造过程,增强代码的可重用性。
抽象 :index.ts 中的客户端代码保持简单并专注于高级逻辑,而提示构造的复杂性在构建器类中被抽象化。
如果您有任何疑问或想进一步讨论,请随时与我联系。
编码愉快!
以上是掌握构建器模式:创建动态 AI 提示生成器 CLI的详细内容。更多信息请关注PHP中文网其他相关文章!