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

تسلسل الدوال (Method Chaining)

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

تسلسل الأساليب هو تقنية تُعيد فيها الأساليب الكائنَ المستقبِل، مما يسمح بربط استدعاءات أساليب متعددة معًا في تعليمة واحدة. لقد رأيت هذا بالفعل في نمط Builder، لكنه مفهوم مستقل مفيد في العديد من السياقات.

يتمثل key في إعادة مؤشر إلى البنية من كل طريقة:

type Query struct {
    table   string
    columns []string
    where   string
    limit   int
}

func (q *Query) Select(cols ...string) *Query {
    q.columns = cols
    return q
}

func (q *Query) From(table string) *Query {
    q.table = table
    return q
}

func (q *Query) Where(condition string) *Query {
    q.where = condition
    return q
}

func (q *Query) Limit(n int) *Query {
    q.limit = n
    return q
}

يمكنك الآن chain هذه الاستدعاءات fluently:

query := &Query{}
query.Select("name", "email").From("users").Where("active = true").Limit(10)

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

تذكّر أن كل method يجب أن تستخدم مستقبِل مؤشر وتُرجع *StructType لكي تعمل chain بشكل صحيح.

challenge icon

التحدي

سهل

لنَبْنِ مُنشئ HTML fluently لـ HTML element يستخدم method chaining لإنشاء وسوم HTML مع attributes وcontent! هذا تطبيق عملي لـ method chaining: ستنشئ API تُقرأ تقريبًا مثل اللغة الطبيعية عند بناء عناصر HTML.

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

  • element.go: Define مُنشئ HTML element الخاص بك باستخدام أساليب قابلة للسلسلة.

    أنشئ بنية Element تخزّن اسم الوسم، وخريطة من attributes (من string إلى string)، وinner content. أنشئ هذه الأساليب القابلة للسلسلة، بحيث يعيد كل منها *Element:

    • NewElement(tag string) - مُنشئ creates عنصرًا جديدًا من نوع Element باسم الوسم given وخريطة attributes initialized (empty)
    • Attr(key, value string) - يضيف attribute إلى element
    • ID(id string) - أسلوب convenience يعيّن "id" attribute
    • Class(class string) - أسلوب convenience يعيّن "class" attribute
    • Content(text string) - يعيّن inner content للعنصر

    أضف أسلوب Render() يعيد سلسلة HTML. ينبغي أن appear الـ attributes بترتيب alphabetical حسب المفتاح. التنسيق هو:

    <tag attr1="value1" attr2="value2">content</tag>

    إذا لم توجد attributes، فاكتفِ بعرض <tag>content</tag>. وإذا لم يوجد content، فاعرض <tag attr="value"></tag>.

  • main.go: ابنِ عناصر HTML باستخدام method chaining.

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

    • id متبوعًا بقيمة ID
    • class متبوعًا بقيمة class
    • attr متبوعًا باسم وقيمة attribute (سطران)
    • content متبوعًا بنص content

    اربط جميع العمليات معًا fluently، ثم اطبع HTML المُصيَّر.

سيتم توفير المدخلات التالية:

  • السطر 1: اسم الوسم
  • السطر 2: عدد العمليات
  • الأسطر التالية: نوع العملية والقيمة (أو القيم)

على سبيل المثال، given:

div
3
id
container
class
main-content
content
Hello World

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

<div class="main-content" id="container">Hello World</div>

وب given:

a
3
attr
href
https://example.com
attr
target
_blank
content
Click here

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

<a href="https://example.com" target="_blank">Click here</a>

وب given:

input
2
attr
type
text
attr
placeholder
Enter name

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

<input placeholder="Enter name" type="text"></input>

وب given:

p
1
content
Simple paragraph

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

<p>Simple paragraph</p>

لاحظ كيف يتيح لك method chaining بناء العناصر خطوة بخطوة بطريقة سهلة القراءة. كل أسلوب يعدّل element ويعيده، مما يسمح بربط استدعاء الأسلوب التالي به مباشرةً.

جرّب بنفسك

package main

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

func main() {
	scanner := bufio.NewScanner(os.Stdin)

	// اقرأ اسم الوسم
	scanner.Scan()
	tagName := scanner.Text()

	// اقرأ عدد العمليات
	scanner.Scan()
	numOps, _ := strconv.Atoi(scanner.Text())

	// أنشئ العنصر
	element := NewElement(tagName)

	// عالج كل عملية
	for i := 0; i < numOps; i++ {
		scanner.Scan()
		operation := scanner.Text()

		// TODO: بناءً على نوع العملية، اربط الطريقة المناسبة
		// يمكن أن تكون العمليات: "id" أو "class" أو "attr" أو "content"
		// - لـ "id": اقرأ السطر التالي كقيمة المعرف
		// - لـ "class": اقرأ السطر التالي كقيمة الصنف
		// - لـ "attr": اقرأ السطرين التاليين (اسم السمة، ثم القيمة)
		// - لـ "content": اقرأ السطر التالي كنص المحتوى
		// استخدم تسلسل الطرق لبناء العنصر بسلاسة

		_ = operation // احذف هذا السطر عند التنفيذ
	}

	// اطبع الـ HTML المُصيَّر
	fmt.Println(element.Render())
}
quiz iconاختبر نفسك

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

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

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