Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

نمط Builder في Go

جزء من قسم البرمجة كائنية التوجه في رحلة GO على Coddy. الدرس 80 من 107.

يفصل نمط Builder بين بناء كائن معقّد وتمثيله. وعلى خلاف نمط الخيارات الوظيفية، يستخدم Builder بنية مخصّصة باسم builder، مع أساليب تهيّئ الكائن خطوةً بخطوة.

إليك كيفية تنفيذ builder لطلب HTTP:

type Request struct {
    method  string
    url     string
    headers map[string]string
    body    string
}

type RequestBuilder struct {
    request *Request
}

func NewRequestBuilder() *RequestBuilder {
    return &RequestBuilder{
        request: &Request{
            headers: make(map[string]string),
        },
    }
}

func (b *RequestBuilder) Method(m string) *RequestBuilder {
    b.request.method = m
    return b
}

func (b *RequestBuilder) URL(u string) *RequestBuilder {
    b.request.url = u
    return b
}

func (b *RequestBuilder) Header(key, value string) *RequestBuilder {
    b.request.headers[key] = value
    return b
}

func (b *RequestBuilder) Build() *Request {
    return b.request
}

يعيد كل method مؤشر builder، مما يتيح chaining للـ method. تعمل method Build() على إنهاء وإرجاع الكائن constructed:

req := NewRequestBuilder().
    Method("POST").
    URL("https://api.example.com").
    Header("Content-Type", "application/json").
    Build()

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

challenge icon

التحدي

سهل

لنَبْنِ مُنشئ رسائل email باستخدام نمط Builder! تحتوي رسائل email على العديد من المكوّنات الاختيارية، مثل المستلمين وCC وsubject وbody والمرفقات، مما يجعلها مرشّحًا مثاليًا للإنشاء خطوةً بخطوة باستخدام method chaining.

ستنظّم شيفرتك عبر ملفين:

  • email.go: عرّف بنية email وbuilder الخاص بها.

    أنشئ بنية Email مع هذه الحقول:

    • from (string)
    • to (slice of strings)
    • cc (slice of strings)
    • subject (string)
    • body (string)

    أنشئ بنية EmailBuilder تحتوي على pointer إلى Email قيد الإنشاء. نفّذ NewEmailBuilder() التي تُرجع builder جديدًا مع Email مُهيّأ (شرائح empty لكلٍّ من to وcc).

    أضف methods الـbuilder التالية، بحيث تُرجع كل واحدة منها *EmailBuilder لإتاحة chaining:

    • From(address string) - تضبط المرسل
    • To(address string) - تضيف recipient إلى شريحة to
    • CC(address string) - تضيف recipient إلى شريحة cc
    • Subject(subject string) - تضبط سطر subject
    • Body(body string) - تضبط body الخاص بـemail

    أضف method باسم Build() تُرجع *Email المُنشأ.

    Finally، أضف method باسم Summary() إلى Email، بحيث تُرجع string بهذا التنسيق:

    From: [from]
    To: [comma-separated to addresses]
    CC: [comma-separated cc addresses or "none"]
    Subject: [subject]
    Body: [body]
  • main.go: أنشئ رسائل email واعرضها باستخدام builder.

    اقرأ عنوان المرسل، ثم اقرأ number المستلمين وعنوان كل recipient. بعد ذلك، اقرأ number مستلمي CC وعنوان كل واحد منهم. Finally، اقرأ subject وbody.

    استخدم EmailBuilder مع method chaining لإنشاء email، ثم اطبع ملخّصه.

ستُزوَّد بالمدخلات التالية:

  • السطر 1: عنوان المرسل
  • السطر 2: number المستلمين
  • الأسطر التالية: عنوان كل recipient
  • السطر التالي: number مستلمي CC
  • الأسطر التالية: عنوان كل مستلم CC
  • السطر التالي: subject
  • السطر الأخير: body

على سبيل المثال، عند إعطاء:

alice@company.com
2
bob@company.com
carol@company.com
1
manager@company.com
Weekly Report
Please find the weekly report attached.

يجب أن يكون الناتج:

From: alice@company.com
To: bob@company.com, carol@company.com
CC: manager@company.com
Subject: Weekly Report
Body: Please find the weekly report attached.

وعند إعطاء:

support@service.com
1
customer@email.com
0
Your Ticket Update
Your support ticket has been resolved.

يجب أن يكون الناتج:

From: support@service.com
To: customer@email.com
CC: none
Subject: Your Ticket Update
Body: Your support ticket has been resolved.

لاحظ كيف يتيح لك builder إضافة عدة مستلمين واحدًا تلو الآخر من خلال استدعاءات To() المتكررة، وكيف يحافظ النمط على كون عملية الإنشاء نظيفة وسهلة القراءة حتى مع وجود العديد من الحقول الاختيارية.

جرّب بنفسك

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// اقرأ عنوان المرسل
	from, _ := reader.ReadString('\n')
	from = strings.TrimSpace(from)

	// اقرأ عدد المستلمين
	toCountStr, _ := reader.ReadString('\n')
	toCount, _ := strconv.Atoi(strings.TrimSpace(toCountStr))

	// اقرأ عنوان كل مستلم
	toAddresses := make([]string, toCount)
	for i := 0; i < toCount; i++ {
		addr, _ := reader.ReadString('\n')
		toAddresses[i] = strings.TrimSpace(addr)
	}

	// اقرأ عدد مستلمي CC
	ccCountStr, _ := reader.ReadString('\n')
	ccCount, _ := strconv.Atoi(strings.TrimSpace(ccCountStr))

	// اقرأ كل عنوان CC
	ccAddresses := make([]string, ccCount)
	for i := 0; i < ccCount; i++ {
		addr, _ := reader.ReadString('\n')
		ccAddresses[i] = strings.TrimSpace(addr)
	}

	// اقرأ الموضوع
	subject, _ := reader.ReadString('\n')
	subject = strings.TrimSpace(subject)

	// اقرأ النص
	body, _ := reader.ReadString('\n')
	body = strings.TrimSpace(body)

	// TODO: استخدم EmailBuilder مع تسلسل الطرق لإنشاء البريد الإلكتروني
	// ابدأ بـ NewEmailBuilder()، ثم سلسل From()، To()، CC()، Subject()، Body()
	// أخيرًا استدعِ Build() للحصول على Email

	// TODO: اطبع ملخص البريد الإلكتروني باستخدام الطريقة Summary()
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم Go عبر الإنترنت