Pernahkah anda mendapati diri anda perlu membuat pelbagai variasi keluarga objek yang berbeza dalam aplikasi anda tanpa menduplikasi logik berulang kali?
Atau mungkin anda telah membina aplikasi, hanya untuk menyedari bahawa keperluan baharu atau perubahan keutamaan pelanggan menuntut objek baharu sepenuhnya, memaksa anda mengolah semula keseluruhan pangkalan kod anda?
Bagaimana jika ada cara untuk lancar memperkenalkan variasi baharu tanpa melanggar kod sedia ada anda hanya dengan memasukkan perlaksanaan baharu?
Di situlah corak reka bentuk Kilang Abstrak masuk!
Dalam tutorial ini, kami akan memecahkan corak reka bentuk yang berkuasa ini dengan membina aplikasi Node.js CLI untuk mencipta pelbagai jenis resume yang menyokong berbilang format dan tema.
Kilang Abstrak ialah corak reka bentuk ciptaan , iaitu kategori corak reka bentuk yang menangani masalah berbeza yang datang dengan cara asli mencipta objek menggunakan kata kunci atau pengendali baharu.
Anda boleh menganggap corak reka bentuk Kilang Abstrak sebagai generalisasi corak reka bentuk kaedah kilang yang telah kami bincangkan dalam artikel blog ini.
Corak reka bentuk Kilang Abstrak menyelesaikan masalah berikut:
Corak reka bentuk Kilang Abstrak menyelesaikan masalah ini dengan mengisytiharkan antara muka atau kelas abstrak untuk setiap jenis produk.
export abstract class PDFResume {} export abstract class JSONResume {} export abstract class MarkdownResume {}
Dan kemudian, seperti yang ditunjukkan oleh nama corak, kami mencipta kilang abstrak yang merupakan antara muka yang mengisytiharkan kaedah kilang yang mencipta setiap jenis produk:
export interface ResumeFactory { createPDFResume(): PDFResume createMarkdownResume(): MarkdownResume createJSONResume(): JSONResume }
Baiklah, kini kami mempunyai kilang generik yang mengembalikan setiap jenis produk yang mungkin, tetapi bagaimana kami boleh menyokong berbilang varian bagi setiap produk?
Jawapannya ialah dengan mewujudkan ConcreteFactory yang melaksanakan kilang abstrak ( ResumeFactory ).
export abstract class PDFResume {} export abstract class JSONResume {} export abstract class MarkdownResume {}
Kini, untuk menggunakan kilang kami dalam kelas pelanggan kami, kami hanya perlu mengisytiharkan pembolehubah jenis ResumeFactory dan kemudian membuat instantiate Kilang konkrit yang sepadan bergantung pada input pengguna.
Kod pelanggan:
export interface ResumeFactory { createPDFResume(): PDFResume createMarkdownResume(): MarkdownResume createJSONResume(): JSONResume }
Struktur corak reka bentuk Kilang Abstrak terdiri daripada kelas berikut:
Dalam kes kami, kaedah kilang yang diisytiharkan dalam Kilang ialah: createProductA dan createProductB
ConcretProductA1 dan ConcretProductA2 melaksanakan IProductA ConcretProductB1 dan ConcretProductB2 melaksanakan IProductB
Dalam bahagian ini, kami akan melaksanakan contoh sebelumnya ke dalam tindakan dengan membina Aplikasi CLI Node.js TypeScript yang berfungsi sepenuhnya yang mencipta resume berdasarkan tema dan format yang dipilih oleh pengguna.
Sila lihat kod berfungsi penuh dengan mengklon repositori ini pada mesin anda.
Kemudian jalankan arahan berikut:
export abstract class PDFResume {} export abstract class JSONResume {} export abstract class MarkdownResume {}
Mari kita mulakan dengan mengisytiharkan jenis yang akan kita gunakan sepanjang tutorial untuk memastikan keselamatan jenis.
antara muka/Jenis
export interface ResumeFactory { createPDFResume(): PDFResume createMarkdownResume(): MarkdownResume createJSONResume(): JSONResume }
Sekarang, mari kita isytiharkan jenis kilang generik, yang akan mentakrifkan tiga kaedah kilang yang sepadan dengan jenis produk yang disokong yang berbeza: PDFResume , MarkdownResume , dan JSONResume.
antara muka/ResumeFactory
export class CreativeResumeFactory implements ResumeFactory { createPDFResume(): CreativePDFResume { return new CreativePDFResume() // CreativePDFResume implements PDFResume } createMarkdownResume(): CreativeMarkdownResume { return new CreativeMarkdownResume() // CreativeMarkdownResume implements MarkdownResume } createJSONResume(): CreativeJSONResume { return new CreativeJSONResume() // CreativeJSONResume implements JSONResume } }
Kami akan meneliti kod mereka dalam bahagian seterusnya.
Seterusnya, mari kita teruskan untuk mencipta kelas produk generik kami.
Setiap jenis produk akan menjadi kelas abstrak kerana kami ingin berkongsi kedua-dua atribut dan kaedah antara subjenis yang sepadan.
Kelas mentakrifkan:
resume/json/JSONResume
// User inputs... let theme = "minimalist" let format = "pdf" let factory: ResumeFactory switch (theme) { case "minimalist": factory = new MinimalistResumeFactory() break case "modern": factory = new ModernResumeFactory() break case "creative": factory = new CreativeResumeFactory() break default: throw new Error("Invalid theme.") } const userInput = await getUserInput() let resume switch (format) { case "pdf": resume = factory.createPDFResume() break case "markdown": resume = factory.createMarkdownResume() break case "json": resume = factory.createJSONResume() break default: throw new Error("Invalid format.") }
Abstrak kata kunci bermaksud bahawa kelas ialah jenis generik yang tidak boleh digunakan; ia hanya boleh diwarisi oleh kelas lain.
Kelas mentakrifkan:
resume/markdown/MarkdownResume
export abstract class PDFResume {} export abstract class JSONResume {} export abstract class MarkdownResume {}
Kelas ini mempunyai objek doc jenis dilindungi PDFKit.PDFDocument , yang diimport daripada pustaka bernama pdfkit. Perpustakaan memudahkan mencipta dan memanipulasi dokumen PDF melalui antara muka berorientasikan objeknya.
Kelas mentakrifkan:
resume/pdf/PDFResume
export interface ResumeFactory { createPDFResume(): PDFResume createMarkdownResume(): MarkdownResume createJSONResume(): JSONResume }
Sekarang kami telah menentukan jenis produk generik dan kilang abstrak kami, tiba masanya untuk meneruskan penciptaan ConcreteFactories kami yang sepadan dengan varian berbeza bagi setiap jenis produk generik.
Kami mempunyai 3 kemungkinan varian untuk resume: Kreatif , Minimalist dan Moden. Dan 3 jenis Produk generik: JSON , PDF dan Markdown.
Kilang abstrak ( ResumeFactory ) mentakrifkan 3 kaedah kilang yang bertanggungjawab untuk mencipta produk kami:
Untuk menyokong pelbagai varian bagi setiap produk, kami perlu mewujudkan 3 kilang konkrit.
Setiap Kilang konkrit akan mencipta 3 jenis produk tetapi dengan perisa tersendiri:
kilang/CreativeResumeFactory
export class CreativeResumeFactory implements ResumeFactory { createPDFResume(): CreativePDFResume { return new CreativePDFResume() // CreativePDFResume implements PDFResume } createMarkdownResume(): CreativeMarkdownResume { return new CreativeMarkdownResume() // CreativeMarkdownResume implements MarkdownResume } createJSONResume(): CreativeJSONResume { return new CreativeJSONResume() // CreativeJSONResume implements JSONResume } }
kilang/MinimalistResumeFactory
// User inputs... let theme = "minimalist" let format = "pdf" let factory: ResumeFactory switch (theme) { case "minimalist": factory = new MinimalistResumeFactory() break case "modern": factory = new ModernResumeFactory() break case "creative": factory = new CreativeResumeFactory() break default: throw new Error("Invalid theme.") } const userInput = await getUserInput() let resume switch (format) { case "pdf": resume = factory.createPDFResume() break case "markdown": resume = factory.createMarkdownResume() break case "json": resume = factory.createJSONResume() break default: throw new Error("Invalid format.") }
kilang/ModernResumeFactory
export abstract class PDFResume {} export abstract class JSONResume {} export abstract class MarkdownResume {}
Sekarang, mari buat ConcreteProducts sebelumnya yang dikembalikan oleh CreativeResumeFactory
Resume PDF :
resume/pdf/CreativePDFResume
export interface ResumeFactory { createPDFResume(): PDFResume createMarkdownResume(): MarkdownResume createJSONResume(): JSONResume }
Resume Markdown :
resume/markdown/CreativeMarkdownResume
export class CreativeResumeFactory implements ResumeFactory { createPDFResume(): CreativePDFResume { return new CreativePDFResume() // CreativePDFResume implements PDFResume } createMarkdownResume(): CreativeMarkdownResume { return new CreativeMarkdownResume() // CreativeMarkdownResume implements MarkdownResume } createJSONResume(): CreativeJSONResume { return new CreativeJSONResume() // CreativeJSONResume implements JSONResume } }
JSON Resume :
resume/json/CreativeJSONResume
// User inputs... let theme = "minimalist" let format = "pdf" let factory: ResumeFactory switch (theme) { case "minimalist": factory = new MinimalistResumeFactory() break case "modern": factory = new ModernResumeFactory() break case "creative": factory = new CreativeResumeFactory() break default: throw new Error("Invalid theme.") } const userInput = await getUserInput() let resume switch (format) { case "pdf": resume = factory.createPDFResume() break case "markdown": resume = factory.createMarkdownResume() break case "json": resume = factory.createJSONResume() break default: throw new Error("Invalid format.") }
Seterusnya, mari buat ConcreteProducts sebelumnya yang dikembalikan oleh MinimalistResumeFactory
Resume PDF :
resume/pdf/MinimalistPDFResume
npm install npm start
Resume Markdown :
resume/markdown/MinimalistMarkdownResume
export type ResumeData = { name: string email: string phone: string experience: Experience[] } export type Experience = { company: string position: string startDate: string endDate: string description: string }
JSON Resume :
resume/json/MinimalistJSONResume
import { JSONResume } from "../resumes/json/JSONResume" import { MarkdownResume } from "../resumes/markdown/MarkdownResume" import { PDFResume } from "../resumes/pdf/PdfResume" export interface ResumeFactory { createPDFResume(): PDFResume createMarkdownResume(): MarkdownResume createJSONResume(): JSONResume }
Akhir sekali, mari buat ConcreteProducts sebelumnya yang dikembalikan oleh ModernResumeFactory
Resume PDF :
resume/pdf/ModernPDFResume
import * as fs from "fs/promises" import { ResumeData } from "../../interfaces/Types" export abstract class JSONResume { protected data!: ResumeData & { style: string } abstract generate(data: ResumeData): void async saveToFile(fileName: string): Promise<void> { await fs.writeFile(fileName, JSON.stringify(this.data, null, 2)) } getData(): any { return this.data } }
Resume Markdown :
resume/markdown/ModernMarkdownResume
import * as fs from "fs/promises" import { ResumeData } from "../../interfaces/Types" export abstract class MarkdownResume { protected content: string = "" abstract generate(data: ResumeData): void async saveToFile(fileName: string): Promise<void> { await fs.writeFile(fileName, this.content) } getContent(): string { return this.content } }
JSON Resume :
resume/json/ModernJSONResume
import * as fs from "fs" import PDFDocument from "pdfkit" import { ResumeData } from "../../interfaces/Types" export abstract class PDFResume { protected doc: PDFKit.PDFDocument constructor() { this.doc = new PDFDocument() } abstract generate(data: ResumeData): void async saveToFile(fileName: string): Promise<void> { const stream = fs.createWriteStream(fileName) this.doc.pipe(stream) this.doc.end() await new Promise<void>((resolve, reject) => { stream.on("finish", resolve) stream.on("error", reject) }) } getBuffer(): Buffer { return this.doc.read() as Buffer } }
Mari kita mula membuahkan hasil kerja kita sebelum ini dengan menggunakan kilang kami dalam kod pelanggan.
Lihat bagaimana kini kami boleh menggunakan perpustakaan pembina resume kami dengan cara yang sangat bersih dengan hanya menggunakan kilang kami.
Pengguna hanya perlu menyediakan dua perkara:
index.ts
import { ResumeFactory } from "../interfaces/ResumeFactory" import { CreativeJSONResume } from "../resumes/json/CreativeJSONResume" import { CreativeMarkdownResume } from "../resumes/markdown/CreativeMarkdownResume" import { CreativePDFResume } from "../resumes/pdf/CreativePDFResume" export class CreativeResumeFactory implements ResumeFactory { createPDFResume(): CreativePDFResume { return new CreativePDFResume() // CreativePDFResume extends PDFResume } createMarkdownResume(): CreativeMarkdownResume { return new CreativeMarkdownResume() // CreativeMarkdownResume extends MarkdownResume } createJSONResume(): CreativeJSONResume { return new CreativeJSONResume() // CreativeJSONResume extends JSONResume } }
Kod di atas berfungsi dalam tiga langkah:
Pengguna tidak mengambil berat tentang cara produk dan varian sepadannya dicipta; mereka hanya perlu memilih tema dan format , dan itu sahaja - produk yang sepadan akan dibuat seperti yang diminta.
Kod pelanggan kini mantap untuk perubahan. Jika kami ingin menambah tema atau gaya baharu, kami boleh mencipta kilang baharu yang bertanggungjawab untuk melakukannya.
Kami telah menggunakan perpustakaan kapur untuk mewarnai log terminal kami bergantung pada makna semantiknya.
Untuk mendapatkan input daripada pengguna apl CLI, kami telah menggunakan pakej inquirer, yang menyediakan cara yang sangat menarik dan mesra pengguna untuk mendapatkan pelbagai jenis input daripada pengguna.
utils/userInput
export abstract class PDFResume {} export abstract class JSONResume {} export abstract class MarkdownResume {}
Corak Kilang Abstrak ialah alat yang berkuasa dalam senjata pereka perisian dan pembangun. Ia menyediakan pendekatan berstruktur untuk mencipta keluarga objek berkaitan tanpa menyatakan kelas konkritnya. Corak ini amat berguna apabila:
Dalam contoh praktikal kami, kami telah melihat bagaimana corak Kilang Abstrak boleh digunakan untuk mencipta sistem penjanaan resume yang fleksibel dan boleh dikembangkan. Sistem ini boleh dengan mudah menampung gaya resume baharu atau format output tanpa mengubah suai kod sedia ada, menunjukkan kuasa Prinsip Terbuka/Tertutup dalam tindakan.
Walaupun corak Kilang Abstrak menawarkan banyak faedah, adalah penting untuk ambil perhatian bahawa ia boleh memperkenalkan kerumitan tambahan kepada pangkalan kod anda. Oleh itu, adalah penting untuk menilai sama ada fleksibiliti yang diberikannya diperlukan untuk kes penggunaan khusus anda.
Dengan menguasai corak reka bentuk seperti Kilang Abstrak, anda akan lebih bersedia untuk mencipta sistem perisian yang teguh, fleksibel dan boleh diselenggara. Teruskan meneroka dan menggunakan corak ini dalam projek anda untuk meningkatkan kemahiran reka bentuk perisian anda.
Jika anda mempunyai sebarang soalan atau ingin membincangkan sesuatu dengan lebih lanjut, sila hubungi saya di sini.
Selamat mengekod!
Atas ialah kandungan terperinci Menguasai Corak Kilang Abstrak: Panduan Komprehensif. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!