1. چیستی الگوی فلای‌ویت

1.1 تعریف و مفهوم

الگوی فلای‌ویت یک الگوی طراحی ساختمانی است که هدف اصلی آن کاهش تعداد اشیاء مشترک است، بنابراین حافظه را صرفه‌جویی کرده و عملکرد را بهبود می‌بخشد. الگوی فلای‌ویت با به اشتراک گذاری اشیاء یکسان یا مشابه، ایجاد و مصرف اشیاء را کاهش می‌دهد و بهینه‌سازی عملکرد را دست‌یابی می‌کند.

1.2 تفاوت با الگوهای طراحی دیگر

مقایسه با الگوهای طراحی دیگر، الگوی فلای‌ویت به طور اصلی بر روی به اشتراک گذاری و استفاده مجدد اشیاء تمرکز دارد. این الگو اشیاء را به وضعیت‌های داخلی قابل به اشتراک و وضعیت‌های خارجی غیرقابل به اشتراک تقسیم می‌کند. با به اشتراک گذاری وضعیت‌های داخلی، ایجاد و مصرف حافظه اشیاء را کاهش می‌دهد و کارایی سیستم را بهبود می‌بخشد.

2. ویژگی‌ها و مزایای الگوی فلای‌ویت

ویژگی‌ها و مزایای اصلی الگوی فلای‌ویت شامل موارد زیر می‌شود:

  • استفاده کمتر از حافظه: با به اشتراک گذاری اشیاء یکسان یا مشابه، مصرف حافظه را کاهش می‌دهد.
  • بهبود عملکرد: ایجاد و از بین بردن اشیاء را کاهش داده و عملکرد سیستم را تسریع می‌دهد.
  • پشتیبانی از تعداد زیادی از اشیاء ریز‌دانه: می‌تواند تعداد زیادی از اشیاء ریز‌دانه را بدون اشغال زیاد فضای حافظه ایجاد کند.
  • ساختار سیستم ساده‌تر: با جداسازی وضعیت‌های داخلی و خارجی اشیاء، ساختار و پیچیدگی سیستم را ساده‌تر می‌کند.

3. نمونه‌های کاربردی عملی الگوی فلای‌ویت

الگوی فلای‌ویت می‌تواند در صورت‌های زیر استفاده شود:

  • اشیاء ذرات در بازی‌ها: ویژگی‌های هر شیء ذره می‌تواند به وضعیت‌های داخلی و خارجی تقسیم شود و اشیاء ذرات با ویژگی‌های مشابه می‌توانند به اشتراک گذاشته شوند.
  • اشیاء اتصال در سرورهای شبکه: ویژگی‌های اشیاء اتصال می‌تواند به وضعیت‌های داخلی و خارجی تقسیم شود و اشیاء اتصال موجود می‌توانند قبل از بازیافت مجدد مورد استفاده قرار بگیرند.

4. پیاده‌سازی الگوی فلای‌ویت در Golang

4.1 نمودار کلاس UML

نمودار کلاس UML الگوی فلای‌ویت در Golang به شکل زیر است:

الگوی فلای‌ویت در Golang

4.2 معرفی نمونه

در این نمونه، ما یک ویرایشگر گرافیکی بر اساس الگوی فلای‌ویت ایجاد خواهیم کرد که شامل دایره‌های مختلف رنگ خواهد بود و با به اشتراک گذاری اشیاء دایره با رنگ یکسان، مصرف حافظه را کاهش خواهیم داد.

4.3 مراحل پیاده‌سازی

4.3.1 ایجاد رابط فلای‌ویت و کلاس Concrete Flyweight

ابتدا نیاز است که یک رابط Flyweight برای تعریف عملیات اشیاء به اشتراک گذاشته‌شونده ایجاد کنیم. سپس می‌توانیم یک کلاس ConcreteFlyweight ایجاد کنیم تا رابط Flyweight را پیاده‌سازی و حالت‌های داخلی را شامل شود.

// Flyweight رابطی را برای اشیاء فلای‌ویت تعریف می‌کند
type Flyweight interface {
	Operation(extrinsicState string)
}

// ConcreteFlyweight نماینده‌ی اشیاء فلای‌ویت متصل است که رابط Flyweight را پیاده‌سازی می‌کند
type ConcreteFlyweight struct {
	intrinsicState string
}

// Operation عملیات روش اشیاء به اشتراک گذاشته‌شده را پیاده‌سازی می‌کند
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 ایجاد کنیم تا نشان دهیم چگونه از الگوی فلای‌ویت برای پیاده‌سازی یک ویرایشگر گرافیکی استفاده کنیم.

// کلاس مشتری
type Client struct {
    flyweight Flyweight
}

// عملیات یک عملیات را انجام می‌دهد
func (c *Client) Operation() {
    c.flyweight.Operation("وضعیت خارجی")
}

4.4 ملاحظات پیاده‌سازی و بهترین روش‌ها

4.4.1 به اشتراک گذاری و ایمنی نخ

هنگام استفاده از الگوی flyweight ، باید توجه شود که به اشتراک گذاری وضعیت داخلی و ایمنی نخ مورد توجه قرار می گیرد. از آنجا که اشیاء flyweight توسط چند مشتری به اشتراک گذاری می شوند ، لازم است هماهنگی وضعیت داخلی را تضمین کرد.

4.4.2 مدیریت استخر اشیاء

برای مدیریت و استفاده مجدد اشیاء flyweight ، می توان از استخر اشیاء برای ذخیره اشیاء flyweight ایجاد شده استفاده کرد. استخر اشیاء می تواند نرخ استفاده مجدد اشیاء را افزایش دهد و هزینه ایجاد و نابودی اشیاء را کاهش دهد.

4.4.3 مدیریت خارجی وضعیت اشیاء

الگوی flyweight وضعیت داخلی و خارجی اشیاء را جدا می کند ، اما وضعیت خارجی باید توسط مشتری مدیریت شود. هنگام استفاده از اشیاء flyweight ، مشتری باید وضعیت خارجی را به اشیاء flyweight برای عملیات منتقل کند.

مثال کامل کد

در زیر مثال کامل کد Golang آمده است:

package main

import "fmt"

// Flyweight defines the interface of a flyweight object
type Flyweight interface {
    Operation(extrinsicState string)
}

// ConcreteFlyweight represents a specific flyweight object and implements the Flyweight interface
type ConcreteFlyweight struct {
    intrinsicState string
}

// Operation implements the operation method for shared objects
func (f *ConcreteFlyweight) Operation(extrinsicState string) {
    fmt.Printf("Concrete flyweight object, internal state: %s, external state: %s\n", f.intrinsicState, extrinsicState)
}

// FlyweightFactory class
type FlyweightFactory struct {
    flyweights map[string]Flyweight
}

// GetFlyweight retrieves or creates a flyweight object from the factory
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
}

// Client class
type Client struct {
    flyweight Flyweight
}

// Operation performs an operation
func (c *Client) Operation() {
    c.flyweight.Operation("external state")
}

func main() {
    factory := &FlyweightFactory{
        flyweights: make(map[string]Flyweight),
    }

    flyweight1 := factory.GetFlyweight("A")
    flyweight1.Operation("external state 1")

    flyweight2 := factory.GetFlyweight("B")
    flyweight2.Operation("external state 2")

    client := &Client{
        flyweight: factory.GetFlyweight("A"),
    }
    client.Operation()
}