1. ما هو نمط الـ Flyweight
1.1 التعريف والمفهوم
نمط الـ Flyweight هو نمط تصميم هيكلي يهدف في الأساس إلى تقليل عدد الأشياء المشتركة، مما يوفر الذاكرة ويحسن الأداء. يقلل نمط الـ Flyweight من إنشاء واستهلاك الأشياء عن طريق مشاركة الأشياء نفسها أو الأشياء المماثلة، مما يحقق تحسين الأداء.
1.2 الاختلاف عن أنماط التصميم الأخرى
بالمقارنة مع أنماط التصميم الأخرى، يركز نمط الـ Flyweight بشكل رئيسي على مشاركة وإعادة استخدام الأشياء. يقسم الأشياء إلى حالات داخلية يمكن مشاركتها وحالات خارجية لا يمكن مشاركتها. من خلال مشاركة الحالات الداخلية، يقلل من إنشاء الأشياء واستهلاك الذاكرة، مما يعزز كفاءة النظام.
2. السمات والمزايا لنمط الـ Flyweight
تشمل السمات والمزايا الرئيسية لنمط الـ Flyweight ما يلي:
- تقليل استخدام الذاكرة: يقلل استهلاك الذاكرة من خلال مشاركة الأشياء نفسها أو الأشياء المماثلة.
- تحسين الأداء: يقلل من إنشاء وتدمير الأشياء، مما يعزز سرعة عمل النظام.
- دعم العدد الكبير من الأشياء الدقيقة: يمكن إنشاء عدد كبير من الأشياء الدقيقة دون أخذ مساحة كبيرة في الذاكرة.
- تبسيط هيكل النظام: من خلال فصل الحالات الداخلية والخارجية للأشياء، يبسط هيكل النظام وتعقيده.
3. أمثلة عن التطبيقات العملية لنمط الـ Flyweight
يمكن تطبيق نمط الـ Flyweight في السيناريوهات التالية:
- أجسام الجسيمات في الألعاب: يمكن تقسيم خصائص كل جسيم إلى حالات داخلية وحالات خارجية، ويمكن مشاركة أجسام الجسيمات ذات الخصائص المماثلة.
- أجسام الاتصال في خوادم الشبكة: يمكن تقسيم خصائص أجسام الاتصال إلى حالات داخلية وحالات خارجية، ويمكن إعادة استخدام أجسام الاتصال الحالية قبل إعادة تدويرها.
4. تنفيذ نمط الـ Flyweight في Golang
4.1 رسم بياني لفئة UML
رسم البياني لفئة UML لنمط الـ Flyweight في Golang كما يلي:
4.2 مثال للتقديم
في هذا المثال، سنقوم بإنشاء محرر رسوميات بناءً على نمط الـ Flyweight، يحتوي على دوائر ملونة مختلفة، وتقليل استخدام الذاكرة من خلال مشاركة أشكال الدوائر ذات اللون نفسه.
4.3 خطوات التنفيذ
4.3.1 إنشاء واجهة Flyweight وفئة Concrete Flyweight
أولاً، نحتاج إلى إنشاء واجهة Flyweight
لتحديد عمليات الأشياء المشتركة. ثم يمكننا إنشاء فئة ConcreteFlyweight
لتنفيذ واجهة Flyweight
وتضمن الحالات الداخلية.
// يحدد واجهة الأشياء المشتركة
type Flyweight interface {
Operation(extrinsicState string)
}
// تمثل اسم الفئة الـ Concrete Flyweight الفئة الفعلية للأشياء المشتركة، وتنفذ واجهة Flyweight
type ConcreteFlyweight struct {
intrinsicState string
}
// تنفذ العملية الطريقة الأشياء المشتركة
func (f *ConcreteFlyweight) Operation(extrinsicState string) {
fmt.Printf("أشياء المشتركة الفعلية، الحالة الداخلية: %s، الحالة الخارجية: %s\n", f.intrinsicState, extrinsicState)
}
4.3.2 إنشاء فئة FlyweightFactory
بعد ذلك، يمكننا إنشاء فئة FlyweightFactory
لإدارة ومشاركة أشياء المشتركة. تحتفظ هذه الفئة بقاموس flyweights
لتخزين أشياء المشتركة التي تم إنشاؤها.
// الفئة FlyweightFactory
type FlyweightFactory struct {
flyweights map[string]Flyweight
}
// GetFlyweight يسترد أو ينشئ أشياء مشتركة من المصنع
func (f *FlyweightFactory) GetFlyweight(key string) Flyweight {
if fw, ok := f.flyweights[key]; ok {
return fw
}
flyweight := &ConcreteFlyweight{
intrinsicState: key,
}
f.flyweights[key] = flyweight
return flyweight
}
4.3.3 مثال على استدعاء العميل
أخيرًا، يمكننا إنشاء فئة Client
لتوضيح كيفية استخدام نمط الـ Flyweight لتنفيذ محرر الرسومات.
// الفئة Client
type Client struct {
flyweight Flyweight
}
// Operation تنفيذ عملية
func (c *Client) Operation() {
c.flyweight.Operation("الحالة الخارجية")
}
4.4 الاعتبارات والممارسات الأفضل في التنفيذ
4.4.1 مشاركة الحالة وسلامة التداول
عند استخدام نمط الطائرة الورقية، يجب الانتباه إلى مشاركة الحالة الداخلية وسلامة التداول. نظرًا لأن كائنات الطائرة الورقية مشتركة بين عملاء متعددين، من الضروري ضمان تماسك الحالة الداخلية.
4.4.2 إدارة حوض الكائنات
لإدارة وإعادة استخدام كائنات الطائرة الورقية بشكل أفضل، يمكن استخدام حمامات الكائنات لتخزين كائنات الطائرة الورقية التي تم إنشاؤها. يمكن لحمامات الكائنات زيادة معدل إعادة الاستخدام للكائنات وتقليل العبء الناتج عن إنشاء الكائنات وتدميرها.
4.4.3 إدارة الحالة الخارجية للكائن
يفصل نمط الطائرة الورقية بين الحالة الداخلية والحالة الخارجية للكائنات، ولكن تحتاج الحالة الخارجية إلى إدارة من قبل العميل. عند استخدام كائنات الطائرة الورقية، يحتاج العميل إلى تمرير الحالة الخارجية إلى كائن الطائرة الورقية للعمل.
مثال شفرة كاملة
أدناه مثال كامل لشفرة Golang:
package main
import "fmt"
// يحدد Flyweight واجهة كائن الطائرة الورقية
type Flyweight interface {
Operation(extrinsicState string)
}
// ConcreteFlyweight يمثل كائن الطائرة الورقية المحدد وينفذ واجهة Flyweight
type ConcreteFlyweight struct {
intrinsicState string
}
// العملية تنفذ طريقة العمل للكائنات المشتركة
func (f *ConcreteFlyweight) Operation(extrinsicState string) {
fmt.Printf("كائن الطائرة الورقية الخرساني، الحالة الداخلية: %s، الحالة الخارجية: %s\n", f.intrinsicState, extrinsicState)
}
// فئة FlyweightFactory
type FlyweightFactory struct {
flyweights map[string]Flyweight
}
// GetFlyweight يسترد أو ينشئ كائن طائرة ورقية من المصنع
func (f *FlyweightFactory) GetFlyweight(key string) Flyweight {
if fw, ok := f.flyweights[key]; ok {
return fw
}
flyweight := &ConcreteFlyweight{
intrinsicState: key,
}
f.flyweights[key] = flyweight
return flyweight
}
// العميل الفئة
type Client struct {
flyweight Flyweight
}
// Operation ينفذ عملية
func (c *Client) Operation() {
c.flyweight.Operation("الحالة الخارجية")
}
func main() {
factory := &FlyweightFactory{
flyweights: make(map[string]Flyweight),
}
flyweight1 := factory.GetFlyweight("A")
flyweight1.Operation("الحالة الخارجية 1")
flyweight2 := factory.GetFlyweight("B")
flyweight2.Operation("الحالة الخارجية 2")
client := &Client{
flyweight: factory.GetFlyweight("A"),
}
client.Operation()
}