بلڈر ڈیزائن پیٹرن: پیچیدہ اشیاء کی تعمیر کا ایک بہتر طریقہ

کچھ اشیاء سادہ ہوتی ہیں، جیسے تار، نمبر، یا بولین۔ اسے ایک لائن بنائیں اور آگے بڑھیں۔

دیگر اشیاء جیسے کیروسل ویجیٹس جن کے لیے آئٹمز کی تعداد، آئٹم بلڈر فنکشنز، کنٹرولرز، ہائٹس، ویو پورٹ ریشوز، آٹو پلے سیٹنگز، پیج چینج کال بیکس اور لامحدود اسکرول کنفیگریشن کی ضرورت ہوتی ہے بالکل بھی آسان نہیں ہے۔ یا ایک HTTP درخواست کی طرح جس میں URL، ہیڈرز، تصدیقی ٹوکن، باڈی، ٹائم آؤٹ، اور دوبارہ کوشش کرنے کی منطق کی ضرورت ہوتی ہے۔ یا ایسی اطلاعات جن میں عنوان، باڈی، آئیکن، چینل، ترجیح، آواز، وائبریشن اور ایکشن بٹن کی ضرورت ہوتی ہے۔

اگر آپ کو اس طرح کی کوئی چیز بنانے کی ضرورت ہے تو، ایک آسان طریقہ یہ ہے کہ بہت سے پیرامیٹرز کے ساتھ کنسٹرکٹر کا استعمال کیا جائے۔ یہ کام کرتا ہے، لیکن جیسے جیسے اشیاء زیادہ پیچیدہ ہوتی جاتی ہیں، مسئلہ زیادہ پیچیدہ ہوتا جاتا ہے۔ پیرامیٹرز میں فرق کرنا مشکل ہو جاتا ہے۔ اختیاری پیرامیٹرز کو ہر جگہ null چیکنگ کی ضرورت ہوتی ہے۔ دلائل کی ترتیب اہم ہے اور آسانی سے غلط کیا جا سکتا ہے۔ کنسٹرکٹر کالز اقدار کی دیوار بن جاتی ہیں جنہیں کوئی بھی پڑھنا یا برقرار رکھنا نہیں چاہتا ہے۔

بلڈر ڈیزائن پیٹرن اس مسئلے کو حل کرتا ہے۔ یہ پیچیدہ اشیاء کی ساخت اور نمائندگی کو الگ کرتا ہے، ایک ہی ساخت کے عمل کو پڑھنے میں آسان، مرحلہ وار انٹرفیس کے ذریعے مختلف قسم کی کمپوزیشن بنانے کی اجازت دیتا ہے۔

انڈیکس

شرطیں

اس مضمون کو پڑھنے سے پہلے، آپ کو درج ذیل سے واقف ہونا چاہیے:

  • آبجیکٹ اورینٹڈ پروگرامنگ: کلاسز، کنسٹرکٹرز، اور طریقے

  • تصوراتی سطح پر ڈیزائن پیٹرن کیا ہے؟

  • بنیادی ڈارٹ یا C# نحو

ڈیزائن پیٹرن کے ساتھ کسی پیشگی تجربے کی ضرورت نہیں ہے۔ یہ مضمون پہلے اصولوں سے بلڈر پیٹرن کو متعارف کراتا ہے۔

بلڈر پیٹرن کیا ہے؟

بلڈر پیٹرن ایک تخلیقی ڈیزائن پیٹرن ہے۔ تخلیق کے نمونے اس بات سے نمٹتے ہیں کہ اشیاء کیسے تخلیق کی جاتی ہیں۔ بلڈر پیٹرن خاص طور پر پیچیدہ اشیاء کی تعمیر سے متعلق ہے جو بہت سے تعمیراتی مراحل کی ضرورت ہوتی ہے.

پیٹرن دو خدشات کو الگ کرتے ہیں جو اکثر سادہ کوڈ میں جڑے ہوتے ہیں: کوئی چیز کیا ہے اور آبجیکٹ کیسے بنتا ہے۔ آبجیکٹ کا اپنا ڈیٹا اور رویہ ہوتا ہے۔ بلڈر کنفیگریشن منطق رکھتا ہے اور حتمی آبجیکٹ بنانے سے پہلے مرحلہ وار ترتیب کو جمع کرتا ہے۔

نتیجہ ایک تعمیراتی عمل ہے جو تعمیر کنندہ کو منتقل کرنے کے لئے اقدار کی فہرست کے بجائے تعمیر کی جانے والی شے کی تفصیل کی طرح پڑھتا ہے۔

مسئلہ یہ حل کرتا ہے

بلڈر پیٹرن کے بغیر ایک پیچیدہ ویجیٹ کو ترتیب دینے کا طریقہ یہ ہے:

// constructing a carousel directly — hard to read, easy to get wrong
CarouselSlider.builder(
  options: CarouselOptions(
    height: 200,
    viewportFraction: 0.97,
    enableInfiniteScroll: false,
    autoPlayCurve: Curves.easeIn,
    enlargeCenterPage: true,
    pauseAutoPlayOnManualNavigate: true,
    onPageChanged: onPageChanged,
    autoPlay: false,
  ),
  itemBuilder: (context, index, realIndex) => AdCard(ad: ads[index]),
  itemCount: ads.length,
)

یہ کام کرتا ہے۔ لیکن دیکھیں کہ کیا ہوتا ہے جب آپ کو ایک ہی اسکرین پر دو مختلف carousel بنانے کی ضرورت ہوتی ہے: ایک اشتہارات کے لیے اور دوسرا اکاؤنٹ بیلنس کے لیے۔ دونوں کو مختلف اونچائیوں، ویو پورٹ کے تناسب، آئٹم بلڈرز، اور آئٹم شمار کی ضرورت ہوتی ہے۔ پورے تعمیراتی بلاک کو کاپی کریں، اقدار میں ترمیم کریں، اور اب آپ کے پاس دو بصری طور پر ملتے جلتے، لیکن بالکل مختلف تعمیراتی دیواریں ہیں۔

اگر آپ کو اشتھاراتی کیروسل میں آٹو پلے شامل کرنے کی نئی ضرورت ہے لیکن بیلنس کیروسل نہیں، تو آپ صحیح بلاک تلاش کرنا چاہیں گے، اسے احتیاط سے ٹھیک کریں، اور صحیح بلاک کو ٹھیک کریں۔

گہرا مسئلہ یہ ہے کہ کنفیگریشن منطق پورے کوڈ بیس میں پھیلی ہوئی ہے۔ کوئی بھی جگہ جہاں carousel بنایا جاتا ہے وہ carousel کی ترتیب کی تمام تفصیلات جانتا ہے۔ ایسی کوئی جگہ نہیں ہے جہاں وہ علم رہتا ہے۔

بلڈر پیٹرن کنفیگریشن کے علم کو ایک جگہ جمع کرتا ہے اور اسے صاف انٹرفیس کے ذریعے ظاہر کرتا ہے۔

بنیادی اجزاء

بلڈر پیٹرن کے تین اجزاء ہیں:

مصنوعات

پیچیدہ اشیاء پیدا ہو رہی ہیں۔ میں بلڈر کے بارے میں نہیں جانتا۔ یہ اپنی ترتیب کو برقرار رکھتا ہے اور اس ترتیب کی بنیاد پر کام کرتا ہے۔ پروڈکٹس اکثر پرائیویٹ کنسٹرکٹرز کا استعمال کرتے ہوئے بنائے جاتے ہیں، اس لیے وہ صرف اسی بلڈر سے بنائے جا سکتے ہیں۔

بلڈر

یہ ایک ایسا طبقہ ہے جو ترتیب کو جمع کرتا ہے اور مصنوعات تیار کرتا ہے۔ بلڈر میں ہر طریقہ پروڈکٹ کے ایک پہلو کو ترتیب دیتا ہے اور خود بلڈر کو واپس کرتا ہے۔ یہ واپسی طریقہ کی زنجیر کو قابل بناتا ہے۔ بلڈر کا حتمی طریقہ تیار شدہ مصنوعات تیار کرتا ہے۔

نگرانی (اختیاری)

ایک طبقہ جو جانتا ہے کہ بلڈر کا استعمال کرتے ہوئے ایک مخصوص پہلے سے تشکیل شدہ پروڈکٹ کیسے تیار کرنا ہے۔ ڈائریکٹر اس بارے میں علم کو انکوڈ کرتا ہے کہ کس طرح ایک عام کنفیگریشن بنائی جائے تاکہ کال کرنے والے کو تفصیلات جاننے کی ضرورت نہ پڑے۔ عملی طور پر، فیکٹری کے طریقے اکثر اس کردار کو پورا کرتے ہیں۔

طریقہ زنجیر: روانی انٹرفیس

میتھڈ چیننگ ایک ٹیکنالوجی ہے جو بلڈر کوڈ کو قدرتی طور پر پڑھتی ہے۔ ہر بلڈر کا طریقہ واپس آتا ہے: this (خود بلڈر) اگلا طریقہ کال فوری طور پر پیروی کر سکتا ہے، یا تو اسی لائن پر یا اگلی لائن پر۔

// without method chaining
final builder = RequestBuilder();
builder.setUrl('https://api.example.com/users');
builder.setMethod('POST');
builder.addHeader('Authorization', 'Bearer $token');
builder.setBody({'name': 'John'});
final request = builder.build();

// with method chaining
final request = RequestBuilder()
    .setUrl('https://api.example.com/users')
    .setMethod('POST')
    .addHeader('Authorization', 'Bearer $token')
    .setBody({'name': 'John'})
    .build();

دونوں بالکل ایک جیسے نتائج پیدا کرتے ہیں۔ منسلک ورژن درخواست کو بیان کرنے والے جملے کی طرح پڑھتا ہے۔ غیر مربوط ورژن بیانات کا ایک سلسلہ ہے۔

طریقہ زنجیر کو روانی انٹرفیس بھی کہا جاتا ہے۔ یہ نام قدرتی زبان کی طرح کوڈ کو بائیں سے دائیں یا اوپر سے نیچے تک روانی سے پڑھنے کے طریقے سے آتا ہے۔

یہ فلٹر فنٹیک ایپلی کیشن کا حقیقی پیداواری عمل ہے۔ آپ کی ایپ کو ڈیش بورڈ پر دو مختلف carousels دکھانا چاہیے۔ ایک پروموشنل اشتہارات کے لیے اور دوسرا اکاؤنٹ بیلنس کے لیے۔ ہر carousel کی ایک مختلف ترتیب ہوتی ہے، لیکن ایک ہی بنیادی کنفیگریشن میکانزم کا اشتراک کرتا ہے۔

ترتیب آبجیکٹ

import 'package:flutter/widgets.dart';
import 'package:equatable/equatable.dart';
import 'package:carousel_slider/carousel_slider.dart';

class CarouselArgs extends Equatable {
  final CarouselSliderController? carouselController;
  final int itemCount;
  final Widget Function(BuildContext, int, int) itemBuilder;
  final CarouselOptions options;

  const CarouselArgs({
    this.carouselController,
    required this.itemCount,
    required this.itemBuilder,
    required this.options,
  });

  @override
  List

CarouselArgs اور CarouselOptions ایک کنفیگریشن آبجیکٹ۔ اس میں وہ تمام ڈیٹا ہوتا ہے جس کی آپ کو اپنے carousel کی تعمیر کے لیے ضرورت ہوتی ہے۔ یہ ایک سادہ ڈیٹا کنٹینر ہے جس کی اپنی کوئی ترتیب منطق نہیں ہے۔

مصنوعات

import 'package:flutter/material.dart';
import 'package:carousel_slider/carousel_slider.dart' as n;

class CustomCarousel extends StatelessWidget {
  final CarouselArgs dto;

  // private constructor only the Builder can create this widget
  CustomCarousel._builder(CustomCarouselBuilder builder)
      : dto = builder._dto!;

  @override
  Widget build(BuildContext context) {
    return n.CarouselSlider.builder(
      options: n.CarouselOptions(
        height: dto.options.height,
        viewportFraction: dto.options.viewPortFraction!,
        enableInfiniteScroll: dto.options.enableInfiniteScroll!,
        enlargeCenterPage: dto.options.enlargeCenterPage,
        onPageChanged: dto.options.onPageChanged,
        autoPlayCurve: dto.options.autoplayCurve!,
        autoPlay: dto.options.autoplay!,
      ),
      itemBuilder: dto.itemBuilder,
      itemCount: dto.itemCount,
    );
  }
}

CustomCarousel یہ ایک پروڈکٹ ہے۔ تخلیق کار نجی ہے۔ CustomCarousel._builder. انڈر سکور کا سابقہ ​​اور نامزد کنسٹرکٹر اس بات کو یقینی بناتا ہے کہ اس کلاس سے باہر کوئی بھی اسے انسٹیٹیوٹ نہیں کر سکتا۔ CustomCarousel براہ راست ایک بنانے کا واحد طریقہ بلڈر کا استعمال کرنا ہے۔

یہ جان بوجھ کر ہے۔ تمام carousel کنفیگریشنز کو بلڈر سے گزرنے پر مجبور کرکے، ان کی تصدیق کی جاتی ہے اور مستقل طور پر اسمبل کیا جاتا ہے۔

بلڈر

class CustomCarouselBuilder {
  BuildContext? _context;
  CarouselArgs? _dto;

  CustomCarouselBuilder setArgs(BuildContext context, CarouselArgs value) {
    _context = context;
    _dto = value;
    return this;
  }

  Widget get buildCarousel =>
      CustomCarousel._builder(this).build(_context!);
}

CustomCarouselBuilder یہ ایک بلڈر ہے۔ کہ BuildContext اور CarouselArgs کے ذریعے setArgs. کہ setArgs طریقہ واپسی thisکال کو کنیکٹ کیا جا سکتا ہے۔

buildCarousel یہ آخری مرحلہ ہے۔ اسے پرائیویٹ کنسٹرکٹر کہتے ہیں۔ CustomCarouselیہ خود کو دلیل کے طور پر پاس کرتا ہے اور پھر اسے پکارتا ہے۔ build حتمی ویجیٹ بناتا ہے۔ ایک carousel نہیں بنایا جا سکتا جب تک کہ سیاق و سباق اور دلائل دونوں فراہم نہ کیے جائیں۔

ڈائریکٹر: بلڈر کا استعمال کرتے ہوئے فیکٹری

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:carousel_slider/carousel_slider.dart' as n;

class CarouselWidgetFactory {
  static CustomCarouselBuilder showCarouselAds(
    BuildContext context, {
    void Function(int, n.CarouselPageChangedReason)? onPageChanged,
  }) =>
      CustomCarouselBuilder().setArgs(
        context,
        CarouselArgs(
          itemCount: context.read().dashboardAds.length,
          itemBuilder: (context, index, realIndex) => DashboardAdsList(
            dto: context.read().dashboardAds[index],
          ),
          options: CarouselOptions(
            height: 200,
            viewPortFraction: 0.97,
            enableInfiniteScroll: false,
            autoplayCurve: Curves.easeIn,
            enlargeCenterPage: true,
            pauseAutoPlayOnManualNavigate: true,
            onPageChanged: onPageChanged,
            autoplay: false,
          ),
        ),
      );

  static CustomCarouselBuilder showCarouselAccountBalance(
    BuildContext context, {
    void Function(int, n.CarouselPageChangedReason)? onPageChanged,
  }) =>
      CustomCarouselBuilder().setArgs(
        context,
        CarouselArgs(
          itemCount: context.read().allBalances.length,
          itemBuilder: (context, index, realIndex) => BalanceList(
            dto: context.read().allBalances[index],
          ),
          options: CarouselOptions(
            height: 230,
            viewPortFraction: 1,
            enableInfiniteScroll: false,
            autoplayCurve: Curves.decelerate,
            enlargeCenterPage: true,
            pauseAutoPlayOnManualNavigate: true,
            onPageChanged: onPageChanged,
            autoplay: false,
          ),
        ),
      );
}

CarouselWidgetFactory یہ ایک ڈائریکٹر ہے۔ ہم بخوبی جانتے ہیں کہ ہر مخصوص کیروسل قسم کے لیے بلڈر کو کیسے ترتیب دیا جائے۔ آپ کا ڈیش بورڈ اشتہاری کیروسل کیسا لگتا ہے اس کا علم (اونچائی 200، ویو پورٹ 0.97، ایزی ان وکر) ایک جگہ پر ہے۔ اکاؤنٹ بیلنس کیروسل کیسا لگتا ہے اس کا علم (اونچائی 230، ویو پورٹ 1، سست روی) ایک جگہ پر ہے۔

جن ڈیولپرز کو نئی کیروزل قسم شامل کرنے کی ضرورت ہے وہ ایک جامد طریقہ شامل کرتے ہیں۔ CarouselWidgetFactory. انہیں اندرونی چیزوں کو سمجھنے کی ضرورت نہیں ہے۔ CustomCarouselBuilder یا CustomCarousel. وہ اپنی مرضی کی وضاحت کے لیے فیکٹری کا استعمال کرتے ہیں۔

اس کا استعمال کرتے ہوئے

class DashboardPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // the factory creates the right builder configuration
        // buildCarousel produces the final widget
        CarouselWidgetFactory.showCarouselAds(context).buildCarousel,
        const SizedBox(height: 16),
        CarouselWidgetFactory.showCarouselAccountBalance(context).buildCarousel,
      ],
    );
  }
}

2 carousels، 2 رسیاں۔ کالنگ کوڈ کو carousel کی ترتیب کے بارے میں قطعی طور پر کوئی علم نہیں ہے۔ میں ویو پورٹ اسکیل، آٹو پلے کروز، یا آئٹم بنانے والوں کے بارے میں نہیں جانتا ہوں۔ ہم فیکٹری کو کہتے ہیں جو پروڈکٹ تیار کرنے کے لیے بلڈر کا استعمال کرتی ہے۔ ہر پرت صرف وہی جانتی ہے جو اسے جاننے کی ضرورت ہے۔

حقیقی دنیا کی مثال 2: HTTP درخواست بلڈر

carousel کی مثال ویجٹ کو ترتیب دینے کے لیے ایک بلڈر کو دکھاتی ہے۔ یہ دوسری مثال UI کے بجائے آبجیکٹ کی تخلیق (HTTP کی درخواست کرنا) دکھاتی ہے۔ یہ ڈیٹا طیاروں اور API کلائنٹس کے لیے ایک عام نمونہ ہے۔

مصنوعات

class ApiRequest {
  final String url;
  final String method;
  final Map headers;
  final Map? body;
  final Duration timeout;
  final int maxRetries;

  // private constructor — only the Builder can create ApiRequest
  ApiRequest._({
    required this.url,
    required this.method,
    required this.headers,
    this.body,
    required this.timeout,
    required this.maxRetries,
  });
}

ApiRequest اس میں وہ سب کچھ ہوتا ہے جس کی آپ کو HTTP درخواستیں کرنے کی ضرورت ہوتی ہے۔ ایک وقف کنسٹرکٹر اس بات کو یقینی بناتا ہے کہ اسے ہمیشہ ایک بلڈر کے ساتھ بنایا جاتا ہے جہاں ڈیفالٹس لاگو ہوتے ہیں اور توثیق کی جاتی ہے۔

بلڈر

class ApiRequestBuilder {
  String? _url;
  String _method = 'GET';
  final Map _headers = {};
  Map? _body;
  Duration _timeout = const Duration(seconds: 30);
  int _maxRetries = 0;

  ApiRequestBuilder url(String url) {
    _url = url;
    return this;
  }

  ApiRequestBuilder method(String method) {
    _method = method;
    return this;
  }

  ApiRequestBuilder header(String key, String value) {
    _headers[key] = value;
    return this;
  }

  ApiRequestBuilder bearerToken(String token) {
    _headers['Authorization'] = 'Bearer $token';
    return this;
  }

  ApiRequestBuilder contentType(String type) {
    _headers['Content-Type'] = type;
    return this;
  }

  ApiRequestBuilder body(Map body) {
    _body = body;
    return this;
  }

  ApiRequestBuilder timeout(Duration timeout) {
    _timeout = timeout;
    return this;
  }

  ApiRequestBuilder withRetries(int maxRetries) {
    _maxRetries = maxRetries;
    return this;
  }

  ApiRequest build() {
    if (_url == null || _url!.isEmpty) {
      throw ArgumentError('URL is required to build an ApiRequest');
    }

    return ApiRequest._(
      url: _url!,
      method: _method,
      headers: Map.unmodifiable(_headers),
      body: _body,
      timeout: _timeout,
      maxRetries: _maxRetries,
    );
  }
}

ہر طریقہ ApiRequestBuilder ایک کنفیگریشن ویلیو سیٹ کرتا ہے اور واپس کرتا ہے۔ this. کہ build() طریقہ آخری مرحلہ ہے۔ یقینی بنائیں کہ مطلوبہ فیلڈز موجود ہیں اور ان کو کنفیگر کریں جنہیں تبدیل نہیں کیا جا سکتا۔ ApiRequest.

توجہ فرمائیں _method, _timeoutاور _maxRetries ان سب کے پاس معقول ڈیفالٹس ہیں۔ کال کرنے والوں کو اس کی وضاحت کرنے کی ضرورت نہیں ہے جب تک کہ وہ ڈیفالٹ کو اوور رائڈ نہیں کرنا چاہتے۔ یہ بلڈر اوور کنسٹرکٹر کے اہم فوائد میں سے ایک ہے۔ اختیاری کنفیگریشنز واقعی اختیاری ہیں، بغیر کوئی چیکنگ یا ڈیفالٹ پیرامیٹر ریزولوشن۔

اس کا استعمال کرتے ہوئے

// a standard authenticated POST request
final createUserRequest = ApiRequestBuilder()
    .url('https://api.example.com/users')
    .method('POST')
    .bearerToken(authToken)
    .contentType('application/json')
    .body({'name': 'Oluwaseyi', 'email': 'seyi@example.com'})
    .timeout(const Duration(seconds: 15))
    .build();

// a GET request with retry logic
final getUserRequest = ApiRequestBuilder()
    .url('https://api.example.com/users/$userId')
    .bearerToken(authToken)
    .withRetries(3)
    .build();

// a request with custom headers for a third-party service
final webhookRequest = ApiRequestBuilder()
    .url('https://webhook.example.com/events')
    .method('POST')
    .header('X-API-Key', apiKey)
    .header('X-Webhook-Secret', webhookSecret)
    .contentType('application/json')
    .body(eventPayload)
    .timeout(const Duration(seconds: 5))
    .build();

ہر درخواست اپنے آپ کو ایک بیان کی طرح پڑھتی ہے۔ یہ یو آر ایل، طریقہ، توثیق، باڈی اور ٹائم آؤٹ ہیں۔ آپ ان میں سے ایک کو پڑھ سکتے ہیں اور فوری طور پر سمجھ سکتے ہیں کہ یہ کس قسم کی درخواست ہے اور اس میں کیا شامل ہے۔

اس کا موازنہ کنسٹرکٹر کو براہ راست کال کرنے سے کریں۔

// without Builder — hard to read, parameter order matters
final request = ApiRequest._(
  url: 'https://api.example.com/users',
  method: 'POST',
  headers: {
    'Authorization': 'Bearer $authToken',
    'Content-Type': 'application/json',
  },
  body: {'name': 'Oluwaseyi', 'email': 'seyi@example.com'},
  timeout: const Duration(seconds: 15),
  maxRetries: 0,
);

کنسٹرکٹر ورژن کے لیے تمام فیلڈز اور ان کے آرڈر کو جاننے کی ضرورت ہے۔ بلڈر ورژن آپ کو صرف وہی بتانے کی اجازت دیتا ہے جس کی آپ کو ضرورت ہے اور ایک دستاویز کی طرح پڑھتا ہے۔

C# میں بلڈر پیٹرن

C# میں وہی پیٹرن ظاہر کرتا ہے کہ یہ ایک آفاقی ڈیزائن کا اصول ہے، نہ کہ ڈارٹ کے لیے مخصوص تکنیک۔ C# خاص طور پر بلڈرز کو لاگو کرنے میں مؤثر ہے کیونکہ اس کے طریقہ کار کی زنجیر کے اصول ہیں۔

C# میں HTTP درخواست بلڈر

public class ApiRequest
{
    public string Url { get; }
    public string Method { get; }
    public Dictionary Headers { get; }
    public object? Body { get; }
    public TimeSpan Timeout { get; }
    public int MaxRetries { get; }

    // private constructor
    private ApiRequest(
        string url,
        string method,
        Dictionary headers,
        object? body,
        TimeSpan timeout,
        int maxRetries)
    {
        Url = url;
        Method = method;
        Headers = headers;
        Body = body;
        Timeout = timeout;
        MaxRetries = maxRetries;
    }

    public static ApiRequestBuilder Create() => new ApiRequestBuilder();
}

public class ApiRequestBuilder
{
    private string? _url;
    private string _method = "GET";
    private readonly Dictionary _headers = new();
    private object? _body;
    private TimeSpan _timeout = TimeSpan.FromSeconds(30);
    private int _maxRetries = 0;

    public ApiRequestBuilder Url(string url)
    {
        _url = url;
        return this;
    }

    public ApiRequestBuilder Method(string method)
    {
        _method = method;
        return this;
    }

    public ApiRequestBuilder Header(string key, string value)
    {
        _headers[key] = value;
        return this;
    }

    public ApiRequestBuilder BearerToken(string token)
    {
        _headers["Authorization"] = $"Bearer {token}";
        return this;
    }

    public ApiRequestBuilder ContentType(string contentType)
    {
        _headers["Content-Type"] = contentType;
        return this;
    }

    public ApiRequestBuilder Body(object body)
    {
        _body = body;
        return this;
    }

    public ApiRequestBuilder Timeout(TimeSpan timeout)
    {
        _timeout = timeout;
        return this;
    }

    public ApiRequestBuilder WithRetries(int maxRetries)
    {
        _maxRetries = maxRetries;
        return this;
    }

    public ApiRequest Build()
    {
        if (string.IsNullOrEmpty(_url))
            throw new ArgumentException("URL is required");

        return new ApiRequest(
            _url!,
            _method,
            new Dictionary(_headers),
            _body,
            _timeout,
            _maxRetries
        );
    }
}

اسے C# میں استعمال کرنا

// authenticated POST request
var createUserRequest = ApiRequest.Create()
    .Url("https://api.example.com/users")
    .Method("POST")
    .BearerToken(authToken)
    .ContentType("application/json")
    .Body(new { name = "Oluwaseyi", email = "seyi@example.com" })
    .Timeout(TimeSpan.FromSeconds(15))
    .Build();

// GET with retry logic
var getUserRequest = ApiRequest.Create()
    .Url($"https://api.example.com/users/{userId}")
    .BearerToken(authToken)
    .WithRetries(3)
    .Build();

پیٹرن ایک ہی ہے. طریقہ کار کے نام C# کنونشنز کے مطابق بڑے بنائے گئے ہیں۔ کہ Build() طریقہ آخری مرحلہ ہے۔ ایک پرائیویٹ کنسٹرکٹر لاگو ہوتا ہے۔ نتیجہ بالکل وہی ہے جیسا کہ ڈارٹ۔

C# (ASP.NET) میں UI بلڈر

بلڈر پیٹرن بیک اینڈ سسٹمز میں پیچیدہ اشیاء کی تعمیر کے لیے .NET میں قدرتی طور پر ظاہر ہوتا ہے۔ نوٹیفکیشن بلڈر اس طرح لگتا ہے:

public class Notification
{
    public string Title { get; }
    public string Body { get; }
    public string? ImageUrl { get; }
    public NotificationPriority Priority { get; }
    public Dictionary Data { get; }
    public bool Silent { get; }

    private Notification(
        string title,
        string body,
        string? imageUrl,
        NotificationPriority priority,
        Dictionary data,
        bool silent)
    {
        Title = title;
        Body = body;
        ImageUrl = imageUrl;
        Priority = priority;
        Data = data;
        Silent = silent;
    }

    public static NotificationBuilder Builder(string title, string body)
        => new NotificationBuilder(title, body);
}

public class NotificationBuilder
{
    private readonly string _title;
    private readonly string _body;
    private string? _imageUrl;
    private NotificationPriority _priority = NotificationPriority.Default;
    private readonly Dictionary _data = new();
    private bool _silent = false;

    internal NotificationBuilder(string title, string body)
    {
        _title = title;
        _body = body;
    }

    public NotificationBuilder WithImage(string imageUrl)
    {
        _imageUrl = imageUrl;
        return this;
    }

    public NotificationBuilder WithPriority(NotificationPriority priority)
    {
        _priority = priority;
        return this;
    }

    public NotificationBuilder WithData(string key, string value)
    {
        _data[key] = value;
        return this;
    }

    public NotificationBuilder AsSilent()
    {
        _silent = true;
        return this;
    }

    public Notification Build() => new Notification(
        _title,
        _body,
        _imageUrl,
        _priority,
        new Dictionary(_data),
        _silent
    );
}

// usage
var notification = Notification
    .Builder("New Transaction", "You received NGN 50,000")
    .WithPriority(NotificationPriority.High)
    .WithData("transaction_id", "txn_001")
    .WithData("type", "credit")
    .Build();

var silentNotification = Notification
    .Builder("Background Sync", "")
    .AsSilent()
    .WithData("sync_type", "full")
    .Build();

بلڈر بمقابلہ کنسٹرکٹر بمقابلہ فیکٹری

یہ سمجھنے کے لیے کہ بلڈر بمقابلہ کنسٹرکٹر یا فیکٹری کے طریقے کب استعمال کیے جائیں، آپ کو یہ سمجھنا ہوگا کہ ہر ایک کون سا مسئلہ حل کرتا ہے۔

کوئی راستہ نہیں کنسٹرکٹر یہ صحیح انتخاب ہے اگر اعتراض اتنا آسان ہے کہ تمام پیرامیٹرز کو ایک نظر میں سمجھا جا سکتا ہے اور اس کی اختیاری ترتیب بہت کم ہے۔ ID، نام اور ای میل والے صارفین کو بلڈر کی ضرورت نہیں ہے۔

کوئی راستہ نہیں فیکٹری کا طریقہ یہ صحیح انتخاب ہے اگر آپ کو تخلیق کی جانے والی آبجیکٹ کی قسم کو کنٹرول کرنے کی ضرورت ہے، یا اگر تخلیق کو فوری کرنے کے لیے ٹھوس قسم کا تعین کرنے کے لیے منطق کی ضرورت ہے۔ Repository.create()، جو آپ کے ماحول کے لحاظ سے SqlRepository یا HiveRepository واپس کرتا ہے، ایک فیکٹری ہے۔

کوئی راستہ نہیں بلڈر یہ صحیح انتخاب ہے جب آپ کے آبجیکٹ میں بہت سے اختیاری یا پیچیدہ کنفیگریشن پیرامیٹرز ہوں، جب کنفیگریشن کو متعدد مراحل کی ضرورت ہو، جب آپ تمام مطلوبہ پیرامیٹرز کے موجود ہونے تک کنفیگریشن ملتوی کر کے غلط آبجیکٹ بنانے سے گریز کرنا چاہتے ہیں، یا جب آپ چاہتے ہیں کہ آپ کا کنفیگریشن کوڈ واضح طور پر پڑھنے کے قابل ہو اور خود دستاویزی ہو۔

carousel مثال جان بوجھ کر بلڈر اور فیکٹری کو ایک ساتھ استعمال کرتی ہے۔ فیکٹری نامزد اور پہلے سے ترتیب شدہ انٹری پوائنٹس (showCarouselAds، showCarouselAccountBalance) فراہم کرتی ہے۔ بلڈر پیچیدہ کنفیگریشنز کی مرحلہ وار تعمیر کو سنبھالتا ہے۔ ہر پیٹرن اپنا کام انجام دیتا ہے۔

بلڈر پیٹرن کا استعمال کب کریں۔

بلڈر پیٹرن میں مختلف قسم کے ٹھوس استعمال کے معاملات ہوتے ہیں۔

اس وقت استعمال کریں جب تخلیق کی جانے والی آبجیکٹ میں بہت سے پیرامیٹرز ہوں، خاص طور پر بہت سے اختیاری پیرامیٹرز۔ 10 اختیاری پیرامیٹرز والا نامزد کنسٹرکٹر پڑھنا مشکل ہے اور غلط کنفیگریشن کا شکار ہے۔

یہ بھی ایک اچھا انتخاب ہے اگر آپ کی کنفیگریشن کو متعدد مراحل کی ضرورت ہے جن کی توثیق کسی چیز کو بنانے سے پہلے کی جانی چاہیے۔ بلڈرز کال کرنے سے پہلے مطلوبہ فیلڈز کو موجود ہونے پر مجبور کر سکتے ہیں۔ build().

اس اختیار کو منتخب کریں اگر آپ چاہتے ہیں کہ آپ کا کنفیگریشن کوڈ خود دستاویزی ہو۔ وضاحتی ناموں کے ساتھ سلسلہ بندی کا طریقہ دستاویزات کی طرح ہے۔ قارئین سمجھ سکتے ہیں کہ انٹرنل کو جانے بغیر کیا بنایا جا رہا ہے۔

یہ مفید ہے جب آپ کو ایک ہی چیز کے لیے مختلف نمائندگی کی ضرورت ہو۔ آپ اسی بلڈر کو ٹیسٹ کی درخواستیں، اسٹیجنگ کی درخواستیں، اور پروڈکشن کی درخواستیں بنانے کے لیے استعمال کر سکتے ہیں کہ درخواست کی کلاس میں ترمیم کیے بغیر کون سا طریقہ بلایا جاتا ہے۔

اور اگر آپ غلط اشیاء بنانے سے روکنا چاہتے ہیں تو یہ بھی اچھا کام کرتا ہے۔ پروڈکٹ کے کنسٹرکٹر کو پرائیویٹ بنا کر اور بلڈر کے کنسٹرکٹر کی توثیق شامل کر کے، build() یہ طریقہ اس بات کو یقینی بناتا ہے کہ غلط اشیاء تخلیق نہ ہوں۔

کب استعمال نہ کریں۔

اگر آپ کا اعتراض آسان ہے اور کنسٹرکٹر پہلے سے واضح ہے تو بلڈر پیٹرن سے بچیں۔ دو مطلوبہ پیرامیٹرز والی کلاس میں بلڈر کو شامل کرنا اوور انجینئرنگ ہے جو قدر میں اضافہ کیے بغیر پیچیدگی کا اضافہ کرتا ہے۔

یہ بھی اچھا انتخاب نہیں ہے اگر تغیر پذیری کوئی مسئلہ نہیں ہے اور پراپرٹی سیٹٹرز کے ذریعے تخلیق کے بعد آبجیکٹ کو کنفیگر کیا جا سکتا ہے۔ کچھ اشیاء بلڈر پیٹرن کنفیگریشن سے زیادہ آسان پوسٹ کنفیگریشن کنفیگریشن سے فائدہ اٹھاتی ہیں۔

اور اگر آپ کے تعمیراتی مراحل میں سخت ترتیب ہے جس کا اظہار ایک لکیری بلڈر نہیں کر سکتا، تو اس سے بچنا بہتر ہے۔ اگر مرحلہ A کا نتیجہ مرحلہ B پر عمل درآمد سے پہلے معلوم ہونا ضروری ہے، تو دوسرا نمونہ زیادہ مناسب ہو سکتا ہے۔

نتیجہ

بلڈر ڈیزائن پیٹرن ان مسائل کو حل کرتا ہے جن کا سامنا تمام ڈویلپرز کو اشیاء کے مزید پیچیدہ ہونے پر ہوتا ہے۔ بہت سے پیرامیٹرز والا کنسٹرکٹر ان اقدار کی دیوار بن جاتا ہے جنہیں پڑھنا مشکل، برقرار رکھنا مشکل اور غلط کنفیگریشن کا شکار ہوتا ہے۔ اختیاری پیرامیٹرز کے لیے نال چیکنگ اور ڈیفالٹ ریزولوشن کے طریقے درکار ہوتے ہیں جو کوڈ کے ارادے کو دھندلا دیتے ہیں۔

بلڈر پیچیدہ اشیاء کی تعمیر کو خود اشیاء سے الگ کرتا ہے۔ کنفیگریشن کو تفصیلی طریقہ کالز کے ذریعے مرحلہ وار جمع کیا جاتا ہے۔ تعمیر ایک آخری مرحلے میں ہوتی ہے: حتمی آبجیکٹ کی توثیق اور تخلیق۔ پروڈکٹ کا پرائیویٹ کنسٹرکٹر اس بات کو یقینی بناتا ہے کہ بلڈر کو نظرانداز کرنا ناممکن ہے۔

حقیقی دنیا کے فلٹر فنٹیک ایپلی کیشنز کی کیروسل مثالیں اسے UI سیاق و سباق میں دکھاتی ہیں: ویجیٹ کنفیگریشنز کو جمع کرنے والے بلڈرز، وہ فیکٹریاں جو پہلے سے کنفیگر شدہ بلڈر کالز فراہم کرتی ہیں مخصوص کیروسل اقسام کے لیے، اور پروڈکٹس جو صرف بلڈرز کے ذریعے کنفیگر کیے جا سکتے ہیں۔ نئی carousel قسم شامل کرنے کا مطلب ہے ایک نیا فیکٹری طریقہ۔ carousel کی ترتیب کو تبدیل کرنے کا مطلب ہے متعلقہ فیکٹری کے طریقوں کو تبدیل کرنا۔ کالنگ کوڈ carousel کے اندر کسی بھی چیز کو نہیں چھوتا ہے۔

HTTP درخواست بلڈر ڈیٹا لیئر سیاق و سباق میں ایک ہی نمونہ دکھاتا ہے۔ اس کا مطلب ہے طریقہ زنجیر کے ذریعے مرحلہ وار ترتیب، اختیاری اقدار کے لیے معقول ڈیفالٹس، کنفیگریشن سے پہلے توثیق، اور ایک ناقابل تغیر پروڈکٹ جو غلط حالت میں نہیں بن سکتی۔

طریقہ چیننگ وہی ہے جو آپ کے بلڈر کوڈ کو پڑھنے میں آسان بناتی ہے۔ ہر طریقہ کال ایک بلڈر کو واپس کرتا ہے تاکہ اگلی کال فوری طور پر کی جا سکے۔ زنجیر کو بائیں سے دائیں یا اوپر سے نیچے تک پڑھا جاتا ہے، جیسے کہ شے کو تیار کیا جا رہا ہے۔ یہ صرف جمالیات نہیں ہے۔ یہ وہی ہے جو بلڈر کوڈ کو خود دستاویزی اور وقت کے ساتھ برقرار رکھنے کے قابل بناتا ہے۔

پیچیدہ آبجیکٹ کمپوزیشن ایک مسئلہ ہے جس کا سامنا ہر کوڈبیس کو ہوتا ہے۔ بلڈر پیٹرن یہ ہے کہ تجربہ کار انجینئر اس کو کیسے حل کرتے ہیں۔

Scroll to Top