نمط Abstract Factory
جزء من قسم البرمجة كائنية التوجه في رحلة GO على Coddy. الدرس 88 من 107.
يمدّد Abstract Factory pattern نمط Factory من خلال إنشاء عائلات من الكائنات المرتبطة دون تحديد أنواعها الملموسة. وبدلاً من factory function واحدة، تحدد واجهة factory تنفذها مصانع ملموسة متعددة، بحيث ينتج كل منها مجموعة متسقة من الكائنات المرتبطة.
تخيّل مجموعة أدوات لواجهة المستخدم تحتاج إلى إنشاء أزرار ومربعات اختيار. تتطلب أنظمة التشغيل المختلفة تطبيقات مختلفة، ولكن يجب أن تعمل المكوّنات معًا بشكل متسق:
type Button interface {
Render() string
}
type Checkbox interface {
Check() string
}
// واجهة المصنع التجريدي
type GUIFactory interface {
CreateButton() Button
CreateCheckbox() Checkbox
}ينتج كل مصنع ملموس عائلة من المكوّنات ذات الصلة:
// عائلة Windows
type WindowsButton struct{}
func (w WindowsButton) Render() string { return "Windows Button" }
type WindowsCheckbox struct{}
func (w WindowsCheckbox) Check() string { return "Windows Checkbox" }
type WindowsFactory struct{}
func (w WindowsFactory) CreateButton() Button { return WindowsButton{} }
func (w WindowsFactory) CreateCheckbox() Checkbox { return WindowsCheckbox{} }
// عائلة Mac
type MacButton struct{}
func (m MacButton) Render() string { return "Mac Button" }
type MacCheckbox struct{}
func (m MacCheckbox) Check() string { return "Mac Checkbox" }
type MacFactory struct{}
func (m MacFactory) CreateButton() Button { return MacButton{} }
func (m MacFactory) CreateCheckbox() Checkbox { return MacCheckbox{} }يتعامل كود العميل مع factory interface، مع بقائه مستقلًا عن التطبيقات الملموسة:
func BuildUI(factory GUIFactory) {
button := factory.CreateButton()
checkbox := factory.CreateCheckbox()
fmt.Println(button.Render(), checkbox.Check())
}استخدم Abstract Factory عندما يحتاج نظامك إلى العمل مع عدة families من المنتجات المرتبطة وتريد ضمان استخدام مكوّنات من family نفسها معًا. فهو أكثر تعقيدًا من Factory بسيط، لذا لا تلجأ إليه إلا عندما تحتاج حقًا إلى إدارة families المنتجات.
التحدي
سهللنَبْنِ نظام متجر أثاث باستخدام نمط Abstract Factory! ستنشئ مصانع تنتج عائلات من عناصر الأثاث المرتبطة: إذ ينتج كل مصنع نمطًا متناسقًا (Modern أو Vintage)، مما يضمن توافق الكراسي والطاولات من المصنع نفسه من الناحية الجمالية.
ستنظم التعليمات البرمجية عبر ثلاثة ملفات:
furniture.go: Define واجهات المنتجات وأنواع الأثاث الملموسة.أنشئ واجهتي منتج:
Chairمع method هيSitOn() stringTableمع method هيPlaceItems() string
Implement عائلتين من furniture:
- Modern family: يعيد
ModernChairالقيمةSitting on a sleek modern chair، ويعيدModernTableالقيمةPlacing items on a glass modern table - Vintage family: يعيد
VintageChairالقيمةSitting on an ornate vintage chair، ويعيدVintageTableالقيمةPlacing items on a wooden vintage table
factory.go: Define واجهة المصنع Abstract ومصانع ملموسة.أنشئ واجهة
FurnitureFactoryمع methodين:CreateChair() ChairCreateTable() Table
Implement مصنعين ملموسين:
ModernFactoryالذي ينتجModernChairوModernTableVintageFactoryالذي ينتجVintageChairوVintageTable
أنشئ أيضًا function باسم
GetFactory(style string) FurnitureFactoryيعيد المصنع المناسب استنادًا إلى النمط (modernأوvintage). استخدمModernFactoryافتراضيًا للأنماط غير المعروفة.main.go: استخدم مصانعك لتأثيث الغرف.أنشئ function باسم
FurnishRoom(factory FurnitureFactory) stringتستخدم المصنع لإنشاء كرسي وطاولة، ثم تعيد سلسلة نصية formatted تعرض الإجراءين في سطرين منفصلين.اقرأ إدخال النمط، واحصل على المصنع المناسب، وأثّث غرفة، ثم اطبع النتيجة.
سيتم توفير المدخلات التالية:
- السطر 1: نمط الأثاث (
modernأوvintageأو أي قيمة أخرى)
على سبيل المثال، عند إعطاء:
modernيجب أن يكون الناتج:
Sitting on a sleek modern chair
Placing items on a glass modern tableوعند إعطاء:
vintageيجب أن يكون الناتج:
Sitting on an ornate vintage chair
Placing items on a wooden vintage tableوعند إعطاء:
rusticيجب أن يكون الناتج:
Sitting on a sleek modern chair
Placing items on a glass modern tableلاحظ كيف تعمل function FurnishRoom مع أي مصنع من خلال الواجهة. فهي لا تعرف ما إذا كانت تنشئ أثاثًا Modern أو Vintage. وهذا يضمن أن يأتي كل الأثاث في الغرفة من العائلة نفسها، مع الحفاظ على نمط متناسق!
جرّب بنفسك
package main
import "fmt"
// FurnishRoom تستخدم مصنعاً لإنشاء الأثاث وتُرجع النتيجة
// TODO: نفّذ هذه الدالة
// - استخدم المصنع لإنشاء كرسي وطاولة
// - أعد سلسلة نصية بنتيجة SitOn() في السطر الأول ونتيجة PlaceItems() في السطر الثاني
func FurnishRoom(factory FurnitureFactory) string {
// TODO: أنشئ كرسياً وطاولة باستخدام المصنع
// TODO: أعد سلسلة منسّقة بكلا الإجراءين في أسطر منفصلة
return ""
}
func main() {
var style string
fmt.Scanln(&style)
// TODO: احصل على المصنع المناسب بناءً على style
// TODO: جهّز غرفة باستخدام المصنع
// TODO: اطبع النتيجة
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات الـ OOP في Go
الملفات الخارجيةمساحة العمل والـ Modules في Goالـ Packages والـ Importsالأسماء المصدرة مقابل غير المصدرةمقدمة إلى الـ OOP في Goالـ Structs كـ Classesتعريف الـ Methods في الـ Structsالـ Pointer Receivers مقابل الـ Value Receiversتهيئة الـ Structدوال الـ Constructorمراجعة - آلة حاسبة بسيطة4الواجهات
مقدمة في الواجهاتالتنفيذ الضمنيالواجهة كعقدالواجهة الفارغة (any)تأكيد النوع (Type Assertion)تبديل النوع (Type Switch)تركيب الواجهاتواجهات Stringer و Errorمراجعة - حاسبة الأشكال7التغليف
الحقول المصدرة وغير المصدرةالتغليف على مستوى الحزمةدوال الـ Getter والـ Setterإخفاء المعلومات في Goملخص - سجلات الطلاب10الأنواع العامة (Go 1.18+)
مقدمة في الأنواع العامةمعاملات الأنواعقيود الأنواعالـ Structs العامةحل بديل للـ Methods العامةملخص - المجموعات العامة13أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factoryنمط Abstract Factoryنمط Observerنمط Strategy2تعمق في الأنواع و Structs
الأنواع الأساسية والمركبةتعريفات الأنواع المخصصةStruct TagsStructs مجهولةStructs متداخلةالقيم الصفرية والافتراضيةمراجعة - دفتر العناوين5التركيب بدلاً من الوراثة
لماذا لا تدعم Go الوراثةأساسيات تضمين الـ Structترقية الـ Methodتضمين عدة Structsالتضمين مقابل التجميعحجب الـ Methods المضمنةملخص - الهيكل الهرمي للموظفين8معالجة الأخطاء و OOP
واجهة errorأنواع الأخطاء المخصصةتغليف الأخطاء (fmt.Errorf)أخطاء Sentinelerrors.Is() و errors.As()Panic و Defer و Recoverملخص - File Parser11المكتبة القياسية والبرمجة كائنية التوجه (OOP)
io.Reader و io.Writerواجهة sort.Interfaceواجهة fmt.Stringerencoding/json مع Structsواجهة http.Handlerمراجعة - نماذج REST API14أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبMiddleware كنمط مزين3المؤشرات والذاكرة
أساسيات المؤشرات في Goالمؤشرات إلى الـ Structsالتمرير بالقيمة مقابل التمرير بالمرجعدالة ()newGarbage Collection في Goملخص - بناء Linked List6تعدد الأشكال في Go
تعدد الأشكال عبر InterfacesDuck Typing في Goقواعد استيفاء الـ Interfaceمجموعات متعددة الأشكالحقن التبعيةمراجعة - معالج الدفع9التزامن والبرمجة كائنية التوجه (OOP)
أساسيات الـ Goroutinesالقنوات (Channels) والاتصالالقنوات المخزنة (Buffered) مقابل غير المخزنةجملة Selectsync.Mutex و sync.RWMutexsync.WaitGroupتصميم الـ Structs الآمنة للخيوط (Thread-Safe)مراجعة - Worker Poolتدرّب بنفسك: مترجم Go عبر الإنترنت