فهم نمط المصنع في الأنغلوري

وكثيراً ما تتطلب التطبيقات الحديثة نماذج تتكيف مع مختلف أدوار المستخدمين أو شياطات البيانات أو بيئات التشكيل، وتنشئ يدوياً حالات لكل عملية تقصّد تؤدي إلى ازدواجية في الشفرة، وحالات تبديل هشة، ومنطق التثبت من صحة المواصفات، وتعالج هذه الحالات من خلال توفير آلية مركزية لإنتاج أشياء مثبتة على أساس نوع معين أو تشكيلة محددة.

ويلخص المصنع منطق التأجيل، وبالتالي لم تعد هناك حاجة إلى معرفة أي نوع من أنواع التصنيف للتأجيل أو كيفية تجميع الضوابط، مما يجعل القاعدة الرمزية أكثر عدلا وقابلية للاختبار وقابلية للتصعيد، خاصة عندما يزيد عدد أنواع الشكل إلى أبعد من العطاء، ويدخل النمط الطبيعي في نظام حقن التبعية للأنغر، مما يتيح لكم تسجيل وظائف المصنع كمقدمين ومحقنين.

لماذا تستخدمين "خطة المصانع" لأشكال الديناميكية؟

(أ) أن يُقدِّم بالفعل [(FLT:2]]] لمعالجة سيناريوهات الشكل المعقدة، ولكن نمط المصنع يزيل النسيج الإجرائي الذي يرافق في كثير من الأحيان إنشاء الشكل، وهذه هي المزايا الرئيسية:

  • Reduces code duplication.] instead of repeating similar ] constructions across components or services, you centralize the logical in one factory method. Each form is built by a dedicated builder class, so you write its logical only once.
  • Enhances maintainability.] Adding a new form type means creating a new builder class and registering it in the factory. No existing components need to change, as long as they request forms by type.
  • Allows flexible form formations.] The factory can accept additional parameters (e.g., user permissions, locale, or feature flags) that influence which controls are included or how they are validated.
  • Supports dynamic user interfaces.] When the form type is determined at runtime (for example, from a database record or a route parameter), the factory makes it trivial to immediateiate the correct on the fly.
  • Improves testability.] Each form builder can be unit-tested independently. The factory itself becomes a simple mapping that can be mocked or stubbed in component tests.

وهذه الفوائد قيمة بوجه خاص في تطبيقات المشاريع التي يجب أن تدعم العديد من تدفقات العمل المتميزة، لكل منها مجموعة من الميادين وقواعد التصديق الخاصة به.

خطوات التنفيذ الأساسية

الخطوة 1: تحديد الشكل والتعديد بين الأوجه

البدء بتحديد مجموعة من أنواع الأشكال، واستخدام الشعار يمنع الإطارات ويوفر عقدا واضحا:

export enum FormType {
 Login = 'login',
 Registration = 'registration',
 Feedback = 'feedback',
 Contact = 'contact'
}

ثم تحديد واجهة ستنفذها جميع مكونات البناء، وهذا يضمن أن يعاملها المصنع بتعددية المقاييس:

import { FormGroup } from '@angular/forms';

export interface FormBuilderInterface {
 build(config?: any): FormGroup;
}

ويتيح البارامترات ] الاختيارية للبنّاء تكييف الشكل على أساس البيانات التي تُجرى في وقت ما، مثل القيم المُسبقة للتنقّل أو تعديل قواعد المصادقة على دور المستعمل.

الخطوة 2: إنشاء وحدات بناء محددة

وينفذ كل بناة ملموسة ويعيد تشكيلاً مناسباً ، فعلى سبيل المثال، قد يبدو مبنياً لشكل قطع الأشجار على هذا النحو:

import { FormBuilder, FormGroup, Validators } from '@angular/forms';

export class LoginFormBuilder implements FormBuilderInterface {
 private fb: FormBuilder;

 constructor() {
 this.fb = new FormBuilder();
 }

 build(): FormGroup {
 return this.fb.group({
 email: ['', [Validators.required, Validators.email]],
 password: ['', [Validators.required, Validators.minLength(6)]],
 rememberMe: [false]
 });
 }
}

وقد يشمل بناء استمارة تسجيل ضوابط إضافية والتحقق من صحة الحقول عبر الحدود:

export class RegistrationFormBuilder implements FormBuilderInterface {
 private fb: FormBuilder;

 constructor() {
 this.fb = new FormBuilder();
 }

 build(): FormGroup {
 const form = this.fb.group({
 firstName: ['', Validators.required],
 lastName: ['', Validators.required],
 email: ['', [Validators.required, Validators.email]],
 password: ['', [Validators.required, Validators.minLength(8)]],
 confirmPassword: ['', Validators.required]
 }, { validators: this.matchPasswords });

 return form;
 }

 private matchPasswords(group: FormGroup): { [key: string]: any } | null {
 const password = group.get('password')?.value;
 const confirm = group.get('confirmPassword')?.value;
 return password === confirm ? null : { mismatch: true };
 }
}

ويزداد هذا الهيكل نظيفا: فكل بناة تركز فقط على تفاصيل شكلها الخاص، ويمكنك إعادة استخدام المنطق عن طريق تكوين البنين أو استخدام وظائف المساعدين.

الخطوة 3: بناء فئة المصانع

وفئة المصنع مسؤولة عن رسم شكل لبناعيها المقابل، ويستخدم التنفيذ البسيط بياناً بالمفتاح أو أداة خريطة:

import { Injectable } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormType } from './form-type.enum';
import { LoginFormBuilder } from './login-form.builder';
import { RegistrationFormBuilder } from './registration-form.builder';
import { FeedbackFormBuilder } from './feedback-form.builder';

@Injectable({ providedIn: 'root' })
export class FormFactory {
 private builders = new Map<FormType, FormBuilderInterface>();

 constructor() {
 // Register builders
 this.builders.set(FormType.Login, new LoginFormBuilder());
 this.builders.set(FormType.Registration, new RegistrationFormBuilder());
 this.builders.set(FormType.Feedback, new FeedbackFormBuilder());
 }

 createForm(type: FormType, config?: any): FormGroup {
 const builder = this.builders.get(type);
 if (!builder) {
 throw new Error(`No builder registered for form type: ${type}`);
 }
 return builder.build(config);
 }
}

أما تسجيل البنين داخل المبني فهو مباشر، ولكن بالنسبة للتطبيقات الأكبر، قد تفضل استخدام حقنة الاعتماد على الأنغلار لتوفير البنين، وهذا النهج مشمول فيما بعد.

الخطوة 4: استخدام المفاعل في المكونات

ويمكن للمكونات، مع وجود المصنع، أن تطلب نموذجا دون معرفة تفاصيل تشييده، وعلى سبيل المثال، عنصر يتناول أنواعا متعددة من الأشكال استنادا إلى مواصفات الطريق:

import { Component, OnInit } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormFactory } from './form.factory';
import { FormType } from './form-type.enum';

@Component({
 selector: 'app-dynamic-form',
 template: `