개발 과정에서 복잡한 객체를 다루어야 했던 사례를 접한 적이 있나요? 매개변수가 너무 많아서 중첩될 수도 있고, 구성하는 데 많은 구축 단계와 복잡한 논리가 필요하기 때문일 수도 있습니다.
복잡한 객체의 생성 코드를 매번 헤매거나 고민할 필요 없이 깔끔하고 쉬운 인터페이스로 모듈을 디자인하고 싶을 수도 있습니다!
여기서 빌더 디자인 패턴이 등장합니다!
이 튜토리얼 전체에서 빌더 디자인 패턴에 대한 모든 것을 설명한 다음 빌더 디자인 패턴을 사용하여 DALL-E 3 최적화 이미지 생성 프롬프트를 생성하기 위한 CLI Node.js 애플리케이션을 구축합니다. .
최종 코드는 Github 저장소에서 확인하실 수 있습니다.
Builder는 창조적 디자인 패턴으로, 새 기능을 사용하여 객체를 생성하는 기본 방식에서 발생하는 다양한 문제를 다루는 디자인 패턴 카테고리입니다. 키워드 또는 연산자.
빌더 디자인 패턴은 다음 문제를 해결하는 데 중점을 둡니다.
복잡한 객체를 생성하기 위한 쉬운 인터페이스 제공 : 많은 초기화 단계가 필요한 깊게 중첩된 객체를 상상해 보세요.
객체 자체에서 구성 코드를 분리하여 동일한 객체에서 여러 표현이나 구성을 생성할 수 있습니다.
빌더 디자인 패턴은 객체 생성 책임을 빌더라는 특수 객체에 위임하여 이 두 가지 문제를 해결합니다.
빌더 개체는 원본 개체를 구성하고 생성 과정을 여러 단계로 나눕니다.
각 단계는 일부 비즈니스 로직을 기반으로 개체 속성의 하위 집합을 초기화하는 빌더 개체의 메서드로 정의됩니다.
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 ).
클라이언트 : 클라이언트는 객체의 최상위 소비자, 라이브러리 모듈을 가져오는 사용자 또는 애플리케이션의 진입점으로 생각할 수 있습니다.
감독 : 동일한 빌더 개체라도 개체의 다양한 변형을 생성할 수 있습니다.
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
클라이언트 코드
const promptBuilder = new PromptBuilder() const prompt1 = promptBuilder.buildStep1().buildStep2().build() const prompt2 = promptBuilder.buildStep1().buildStep3().build()위 코드에서 볼 수 있듯이 클라이언트 코드는 프롬프트1이나 프롬프트2를 생성하기 위한 세부 사항을 알 필요가 없습니다. 단지 Director를 호출하고 올바른 빌더 객체를 설정한 다음 makePrompt 메소드를 호출합니다.
실제 시나리오
신속한 엔지니어링 이미지 생성 AI CLI 도구를 처음부터 만들어 보겠습니다.
이 CLI 앱의 소스 코드는 여기에서 확인할 수 있습니다.CLI 도구는 다음과 같이 작동합니다.
파일: 프롬프트.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() } }
파일: 프롬프트.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파일에 정의된 모든 속성 세부정보를 자유롭게 살펴보세요.
enums.tsclass 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에서 큰 문제가 되지 않습니다. 모든 속성이 null을 허용하는 구성 개체를 전달할 수 있기 때문입니다.
프롬프트 구축 프로세스를 추상화하고 코드를 확장을 위해 개방하고 수정을 위해 폐쇄(SOLID의 O)하도록 하고, 라이브러리 클라이언트가 프롬프트 생성 라이브러리를 원활하고 쉽게 사용할 수 있도록 하기 위해, 우리는 빌더 디자인 패턴을 구현하기로 선택할 것입니다.
일반 프롬프트 빌더 인터페이스를 선언하는 것부터 시작하겠습니다.
인터페이스는 다양한 메소드를 선언합니다.
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 클래스 정의로 넘어가겠습니다.
director.ts
const promptBuilder = new PromptBuilder() const prompt1 = promptBuilder.buildStep1().buildStep2().build() const prompt2 = promptBuilder.buildStep1().buildStep3().build()
Director 클래스는 PromptBuilder를 래핑하고 setSubject에서 까지 모든 빌더 메소드를 호출하는 프롬프트 구성을 생성할 수 있게 해줍니다. buildArtisticElements.
이렇게 하면 index.ts 파일의 클라이언트 코드가 단순화되며 다음 섹션에서 살펴보겠습니다.
serializers.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()
위 코드는 다음 작업을 수행합니다.
주의하세요: 빌더 유형별로 제작되는 프롬프트의 모양이 다르기 때문에 디렉터로부터 프롬프트를 받는 것은 불가능합니다.
Builder 디자인 패턴은 AI 이미지 프롬프트 생성 CLI 애플리케이션에서 입증된 것처럼 여러 구성으로 복잡한 객체를 생성하기 위한 탁월한 솔루션임이 입증되었습니다. 이 시나리오에서 Builder 패턴이 유용한 이유는 다음과 같습니다.
단순한 개체 생성 : 이 패턴을 사용하면 복잡한 생성 프로세스를 클라이언트 코드에 노출하지 않고도 복잡한 RealisticPhotoPrompt 및 DigitalArtPrompt 개체를 만들 수 있습니다.
유연성 : 각 프롬프트 유형에 별도의 빌더 클래스를 사용하면 클라이언트 코드를 변경하지 않고도 새 프롬프트 유형을 쉽게 추가하거나 기존 프롬프트 유형을 수정할 수 있습니다.
코드 구성 : 패턴은 구성 논리를 표현과 분리하는 데 도움이 되어 코드를 더욱 모듈화하고 유지 관리하기 쉽게 만들었습니다.
재사용성 : PromptDirector 클래스를 사용하면 다양한 유형의 프롬프트에 대해 동일한 구성 프로세스를 재사용할 수 있어 코드 재사용성이 향상됩니다.
추상화 : index.ts의 클라이언트 코드는 단순하게 유지되고 높은 수준의 논리에 초점을 맞춘 반면 프롬프트 구성의 복잡성은 빌더 클래스에서 추상화되었습니다.
질문이 있으시거나 추가 논의를 원하시면 여기로 연락주세요.
즐거운 코딩하세요!
위 내용은 빌더 패턴 마스터하기: 동적 AI 프롬프트 생성기 CLI 생성의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!