در بعضی پروژههای PHP لازم است تعداد بسیار زیادی Object مشابه ایجاد و نگهداری شود. برای مثال:
- نمایش هزاران درخت در یک نقشه
- مدیریت تعداد زیادی ذره در یک بازی
- نگهداری اطلاعات محصولات مشابه
- مدیریت کاربران یا موجودیتهایی با ویژگیهای تکراری
- نمایش آیتمهای زیاد در یک گزارش
- پردازش دادههایی که بخش زیادی از اطلاعات آنها مشترک است
اگر برای هر Object تمام اطلاعات را بهصورت جداگانه ذخیره کنیم، ممکن است بخش زیادی از حافظه صرف نگهداری دادههای تکراری شود.
برای مثال، فرض کنید ۱۰ هزار محصول داریم که در همه آنها اطلاعات برند، رنگ و تصویر یکسان است، اما شناسه، قیمت و تعداد موجودی متفاوت است. ذخیرهکردن برند، رنگ و تصویر در هر ۱۰ هزار Object میتواند باعث تکرار غیرضروری دادهها شود.
در چنین شرایطی میتوان از Flyweight Pattern استفاده کرد.
Flyweight یکی از الگوهای ساختاری یا Structural Design Patterns است که با اشتراکگذاری بخشهای مشترک State میان چندین Object، تعداد دادههای تکراری را کاهش میدهد. هدف اصلی این الگو کاهش مصرف حافظه در شرایطی است که تعداد زیادی Object مشابه همزمان در حافظه وجود دارند. <Cite refs={["turn0search0","turn0search2"]} />
Flyweight Pattern چیست؟
Flyweight Pattern الگویی است که بخش مشترک اطلاعات چند Object را در یک Object قابل اشتراک ذخیره میکند و اطلاعات اختصاصی هر Object را خارج از آن نگه میدارد.
در این الگو، State مربوط به Object معمولاً به دو بخش تقسیم میشود:
Intrinsic State
اطلاعات مشترک و معمولاً ثابت که میان چند Object استفاده میشود.
مثال:
- نام برند
- رنگ
- تصویر
- نوع محصول
- نام فونت
- نوع درخت
- اطلاعات ثابت یک قالب
Extrinsic State
اطلاعات اختصاصی و وابسته به هر نمونه که میان Objectها متفاوت است.
مثال:
- شناسه محصول
- قیمت
- موقعیت جغرافیایی
- تعداد موجودی
- نام کاربر
- مختصات یک Object
- وضعیت لحظهای یک موجودیت
Flyweight اطلاعات مشترک را نگهداری میکند و اطلاعات اختصاصی را هنگام اجرای متد دریافت میکند. <Cite refs={["turn0search2","turn0search4"]} />
ساختار کلی:
Client
│
▼
Flyweight Factory
│
├── Shared Flyweight A
├── Shared Flyweight B
└── Shared Flyweight C
Context Object
├── Extrinsic State
└── Reference to Flyweight
چرا به Flyweight نیاز داریم؟
فرض کنید کلاس زیر را داریم:
<?php
declare(strict_types=1);
final class Product
{
public function __construct(
public readonly int $id,
public readonly string $brand,
public readonly string $color,
public readonly string $image,
public readonly float $price
) {
}
}
حالا اگر هزاران محصول از یک برند و رنگ یکسان داشته باشیم، اطلاعاتی مانند brand، color و image در تعداد زیادی Object تکرار میشوند.
نسخه ساده استفاده:
$products = [];
for ($i = 1; $i <= 10000; $i++) {
$products[] = new Product(
id: $i,
brand: 'Example Brand',
color: 'Black',
image: 'products/black-laptop.jpg',
price: 50000000
);
}
در این مدل، هر Object اطلاعات مشترک خودش را نگهداری میکند.
Flyweight پیشنهاد میکند اطلاعات مشترک را جدا کنیم:
Product Context
id
price
sharedProductData
Shared Product Data
brand
color
image
در این حالت، تعداد زیادی Product میتوانند به یک Object مشترک اشاره کنند.
اجزای Flyweight Pattern
Flyweight Pattern معمولاً از اجزای زیر تشکیل میشود.
۱. Flyweight
Objectی که State مشترک را نگهداری میکند.
۲. Concrete Flyweight
پیادهسازی واقعی Flyweight که اطلاعات مشترک را در خود دارد.
۳. Flyweight Factory
کلاسی که Flyweightها را ایجاد و مدیریت میکند. Factory ابتدا بررسی میکند آیا Flyweight موردنظر قبلاً ساخته شده است یا خیر. اگر وجود داشته باشد، همان Object را برمیگرداند؛ در غیر این صورت، Object جدید ایجاد میکند. <Cite refs={["turn0search0","turn0search2"]} />
۴. Context
Objectی که State اختصاصی هر نمونه را نگهداری میکند و به Flyweight مشترک ارجاع میدهد.
۵. Client
بخشی از برنامه که از Factory و Context استفاده میکند.
مثال ساده Flyweight در PHP
فرض کنید میخواهیم محصولات یک فروشگاه را مدیریت کنیم. اطلاعاتی مانند برند، رنگ و تصویر میان محصولات زیادی مشترک است؛ اما شناسه، قیمت و موجودی هر محصول اختصاصی است.
تعریف Flyweight
<?php
declare(strict_types=1);
final class ProductVariation
{
public function __construct(
public readonly string $brand,
public readonly string $color,
public readonly string $image
) {
}
public function describe(): string
{
return sprintf(
'%s - %s - %s',
$this->brand,
$this->color,
$this->image
);
}
}
کلاس ProductVariation فقط اطلاعات مشترک را نگهداری میکند.
تعریف Context
<?php
declare(strict_types=1);
final class Product
{
public function __construct(
public readonly int $id,
public readonly float $price,
public readonly int $stock,
private readonly ProductVariation $variation
) {
}
public function describe(): string
{
return sprintf(
'Product #%d | Price: %.2f | Stock: %d | Variation: %s',
$this->id,
$this->price,
$this->stock,
$this->variation->describe()
);
}
}
در این کلاس، اطلاعات اختصاصی مانند شناسه، قیمت و موجودی ذخیره میشود. اطلاعات مشترک در Object مربوط به ProductVariation قرار دارد.
ساخت Flyweight Factory
<?php
declare(strict_types=1);
final class ProductVariationFactory
{
/**
* @var array<string, ProductVariation>
*/
private array $variations = [];
public function get(
string $brand,
string $color,
string $image
): ProductVariation {
$key = $this->createKey(
brand: $brand,
color: $color,
image: $image
);
if (!isset($this->variations[$key])) {
$this->variations[$key] = new ProductVariation(
brand: $brand,
color: $color,
image: $image
);
}
return $this->variations[$key];
}
private function createKey(
string $brand,
string $color,
string $image
): string {
return implode('|', [
$brand,
$color,
$image,
]);
}
public function count(): int
{
return count($this->variations);
}
}
Factory بر اساس اطلاعات مشترک یک Key میسازد. اگر همان Key قبلاً در آرایه وجود داشته باشد، Object قبلی را برمیگرداند.
استفاده از Factory
<?php
$factory = new ProductVariationFactory();
$variationA = $factory->get(
brand: 'Example Brand',
color: 'Black',
image: 'products/black-laptop.jpg'
);
$variationB = $factory->get(
brand: 'Example Brand',
color: 'Black',
image: 'products/black-laptop.jpg'
);
var_dump($variationA === $variationB);
خروجی:
bool(true)
هر دو متغیر به یک Object مشترک اشاره میکنند.
ساخت محصولات
<?php
$productA = new Product(
id: 1,
price: 50000000,
stock: 10,
variation: $variationA
);
$productB = new Product(
id: 2,
price: 52000000,
stock: 4,
variation: $variationB
);
echo $productA->describe() . PHP_EOL;
echo $productB->describe() . PHP_EOL;
echo "Shared variations: {$factory->count()}" . PHP_EOL;
خروجی نمونه:
Product #1 | Price: 50000000.00 | Stock: 10 | Variation: Example Brand - Black - products/black-laptop.jpg
Product #2 | Price: 52000000.00 | Stock: 4 | Variation: Example Brand - Black - products/black-laptop.jpg
Shared variations: 1
در این مثال، دو محصول متفاوت وجود دارد، اما اطلاعات مشترک آنها فقط یک بار در ProductVariation ذخیره شده است.
اهمیت Immutable بودن Flyweight
از آنجا که یک Flyweight ممکن است میان چندین Context استفاده شود، نباید State مشترک آن بهصورت ناخواسته تغییر کند.
به همین دلیل بهتر است اطلاعات Flyweight:
- در Constructor مقداردهی شوند.
- دارای Propertyهای
readonlyباشند. - Setter عمومی نداشته باشند.
- توسط چند بخش مختلف قابل تغییر نباشند.
- اطلاعات اختصاصی هر Context را در خود نگهداری نکنند.
نمونه مناسب:
<?php
declare(strict_types=1);
final class TextStyle
{
public function __construct(
public readonly string $fontFamily,
public readonly int $fontSize,
public readonly string $color
) {
}
}
اگر TextStyle میان هزاران متن استفاده شود، تغییر اطلاعات آن میتواند روی تمام متنهایی که به آن ارجاع دارند اثر بگذارد. بنابراین Immutable بودن Flyweight یک اصل مهم در طراحی آن است. <Cite refs={["turn0search2","turn0search4"]} />
مثال واقعیتر؛ مدیریت درختها در PHP
فرض کنید برنامهای داریم که باید هزاران درخت را روی یک نقشه نمایش دهد.
اطلاعاتی مانند نوع درخت، رنگ برگها و تصویر آن میان بسیاری از درختها مشترک است. اما موقعیت هر درخت متفاوت است.
Flyweight مربوط به نوع درخت
<?php
declare(strict_types=1);
final class TreeType
{
public function __construct(
public readonly string $name,
public readonly string $color,
public readonly string $texture
) {
}
public function draw(int $x, int $y): string
{
return sprintf(
'%s at (%d, %d), color: %s, texture: %s',
$this->name,
$x,
$y,
$this->color,
$this->texture
);
}
}
Context مربوط به هر درخت
<?php
declare(strict_types=1);
final class Tree
{
public function __construct(
private readonly int $x,
private readonly int $y,
private readonly TreeType $type
) {
}
public function draw(): string
{
return $this->type->draw(
x: $this->x,
y: $this->y
);
}
}
Factory درختها
<?php
declare(strict_types=1);
final class TreeTypeFactory
{
/**
* @var array<string, TreeType>
*/
private array $types = [];
public function get(
string $name,
string $color,
string $texture
): TreeType {
$key = "{$name}|{$color}|{$texture}";
if (!isset($this->types[$key])) {
$this->types[$key] = new TreeType(
name: $name,
color: $color,
texture: $texture
);
}
return $this->types[$key];
}
}
استفاده
<?php
$factory = new TreeTypeFactory();
$oak = $factory->get(
name: 'Oak',
color: 'Green',
texture: 'oak.png'
);
$treeA = new Tree(
x: 10,
y: 20,
type: $oak
);
$treeB = new Tree(
x: 50,
y: 80,
type: $oak
);
echo $treeA->draw() . PHP_EOL;
echo $treeB->draw() . PHP_EOL;
در اینجا دو درخت در موقعیتهای مختلف وجود دارند، اما هر دو از یک TreeType مشترک استفاده میکنند.
این مثال نشان میدهد که Flyweight چگونه اطلاعات مشترک را از اطلاعات وابسته به هر نمونه جدا میکند. <Cite refs={["turn0search2","turn0search3"]} />
Intrinsic State و Extrinsic State در عمل
برای تشخیص اینکه چه دادهای باید در Flyweight قرار گیرد، باید هر Property را بررسی کنیم.
| Property | نوع State | دلیل |
|---|---|---|
| نام برند | Intrinsic | میان چند محصول مشترک است |
| رنگ محصول | Intrinsic | در محصولات مشابه تکرار میشود |
| تصویر محصول | Intrinsic | دادهای مشترک و معمولاً حجیم است |
| شناسه محصول | Extrinsic | برای هر محصول متفاوت است |
| قیمت | Extrinsic | ممکن است برای هر محصول متفاوت باشد |
| موجودی | Extrinsic | وابسته به همان نمونه است |
| موقعیت روی نقشه | Extrinsic | برای هر Object متفاوت است |
| نوع فونت | Intrinsic | میان متنهای متعدد قابل اشتراک است |
| مختصات متن | Extrinsic | برای هر متن تغییر میکند |
اگر دادهای در هر نمونه متفاوت است یا در طول زمان تغییر میکند، معمولاً نباید در Flyweight مشترک قرار بگیرد.
Flyweight Factory چه کاری انجام میدهد؟
Factory مسئول مدیریت مجموعه Flyweightهای ایجادشده است.
فرایند معمول آن به شکل زیر است:
- Client اطلاعات مشترک موردنیاز را ارسال میکند.
- Factory یک Key از آن اطلاعات میسازد.
- Factory بررسی میکند آیا Flyweight مربوط به آن Key وجود دارد یا خیر.
- اگر وجود داشته باشد، همان Object بازگردانده میشود.
- اگر وجود نداشته باشد، Factory یک Flyweight جدید میسازد.
- Object جدید در Pool ذخیره میشود.
- Flyweight به Client تحویل داده میشود.
این روش باعث میشود Client مستقیماً مسئول ایجاد و مدیریت Objectهای مشترک نباشد. <Cite refs={["turn0search0","turn0search2"]} />
استفاده احتمالی از Flyweight در Laravel
Flyweight در Laravel در همه پروژهها ضروری نیست، اما در بعضی سناریوها میتواند مفید باشد.
۱. اطلاعات مشترک محصولات
اگر محصولات زیادی اطلاعات مشترکی مانند برند، تصویر، رنگ یا مشخصات ثابت داشته باشند، میتوان اطلاعات مشترک را در Objectهای قابل اشتراک قرار داد.
۲. قالبهای پیامک
فرض کنید تعداد زیادی پیامک با قالبهای یکسان ارسال میشود، اما شماره موبایل و پارامترهای هر پیام متفاوت است.
اطلاعات قالب میتواند Shared State باشد:
<?php
declare(strict_types=1);
final class SmsTemplate
{
public function __construct(
public readonly string $code,
public readonly string $body
) {
}
public function render(array $parameters): string
{
return str_replace(
array_keys($parameters),
array_values($parameters),
$this->body
);
}
}
شماره موبایل و پارامترهای پیام در Context قرار میگیرند.
۳. اطلاعات ثابت سرویسهای n8n
در یک سیستم مدیریت سرویس، ممکن است چندین سرویس از یک نوع Image، تنظیمات عمومی یا مشخصات ثابت استفاده کنند، اما شناسه، وضعیت، کاربر و زمانبندی هر سرویس متفاوت باشد.
اطلاعات ثابت میتواند در یک Object مشترک قرار گیرد؛ البته فقط در صورتی که تعداد Objectها زیاد باشد و اشتراکگذاری واقعاً ارزش داشته باشد.
۴. دادههای ثابت API
اگر چندین درخواست API از یک Provider، Endpoint یا تنظیمات مشترک استفاده کنند، میتوان بخشی از تنظیمات ثابت را در یک Object مشترک نگهداری کرد.
با این حال، در بسیاری از پروژههای Laravel، استفاده از Service Container و Cache معمولاً سادهتر و مناسبتر از پیادهسازی کامل Flyweight است.
تفاوت Flyweight و Singleton
Flyweight و Singleton هر دو ممکن است از یک Object مشترک استفاده کنند، اما هدفشان یکسان نیست.
Singleton
هدف Singleton تضمین وجود یک نمونه از یک کلاس در یک محدوده مشخص است.
Flyweight
هدف Flyweight اشتراکگذاری State مشترک میان تعداد زیادی Object مشابه است.
تفاوتهای مهم:
| Singleton | Flyweight |
|---|---|
| معمولاً یک نمونه دارد | میتواند چند نمونه با Stateهای مختلف داشته باشد |
| هدف آن کنترل تعداد Instance است | هدف آن کاهش دادههای تکراری است |
| ممکن است Mutable باشد | بهتر است Immutable باشد |
| معمولاً دسترسی سراسری ایجاد میکند | معمولاً از Factory برای مدیریت استفاده میکند |
Flyweight فقط به معنی «یک Object برای همهچیز» نیست. ممکن است چند Flyweight مختلف وجود داشته باشد؛ برای مثال یک Flyweight برای رنگ قرمز و یک Flyweight برای رنگ آبی. <Cite refs={["turn0search2"]} />
تفاوت Flyweight و Prototype
Prototype برای ساخت Object جدید از طریق کپیکردن یک Object موجود استفاده میشود.
Flyweight برعکس، تلاش میکند به جای ساخت Objectهای مشابه، همان Object مشترک را دوباره استفاده کند.
| Prototype | Flyweight |
|---|---|
| هدف آن کپیکردن Object است | هدف آن اشتراکگذاری Object است |
| معمولاً Instance جدید ایجاد میکند | معمولاً Instance موجود را برمیگرداند |
| برای ساخت نمونههای مشابه کاربرد دارد | برای کاهش تکرار State کاربرد دارد |
تفاوت Flyweight و Object Pool
Object Pool مجموعهای از Objectهای آماده را مدیریت میکند و آنها را برای استفاده مجدد در اختیار Client قرار میدهد.
Flyweight بیشتر روی اشتراکگذاری State مشترک تمرکز دارد.
برای مثال:
- Connection Pool برای استفاده مجدد از Connectionها کاربرد دارد.
- Thread Pool برای استفاده مجدد از Threadها کاربرد دارد.
- Flyweight برای اشتراکگذاری دادههای مشترک میان Objectها کاربرد دارد.
این دو الگو میتوانند در یک سیستم کنار هم استفاده شوند، اما هدف طراحی آنها متفاوت است.
مزایای Flyweight Pattern
۱. کاهش مصرف حافظه
اگر تعداد زیادی Object اطلاعات تکراری داشته باشند، اشتراکگذاری آن اطلاعات میتواند مصرف حافظه را کاهش دهد.
۲. کاهش دادههای تکراری
اطلاعات مشترک فقط یک بار نگهداری میشود.
۳. مدیریت بهتر Objectهای مشابه
Factory ایجاد و استفاده مجدد از Flyweightها را مدیریت میکند.
۴. جداسازی State مشترک و اختصاصی
تقسیم Intrinsic و Extrinsic State باعث میشود ساختار دادهها واضحتر شود.
۵. امکان استفاده مجدد
یک Flyweight میتواند در Contextهای مختلف استفاده شود.
معایب Flyweight Pattern
۱. افزایش پیچیدگی طراحی
به جای یک کلاس ساده، ممکن است به Flyweight، Context و Factory نیاز داشته باشیم.
۲. افزایش وابستگی به Factory
Client باید برای دریافت Object مشترک از Factory استفاده کند.
۳. احتمال افزایش پردازش
ساخت Key، جستوجو در Pool و مدیریت State ممکن است هزینه پردازشی ایجاد کند.
۴. دشواری در مدیریت State
اگر State مشترک اشتباهاً تغییر کند، تمام Objectهایی که از آن استفاده میکنند تحت تأثیر قرار میگیرند.
۵. کاربرد محدود در PHP
در بسیاری از برنامههای PHP، تمام Objectهای برنامه بهصورت همزمان در حافظه نگهداری نمیشوند. بنابراین Flyweight همیشه بهترین راهحل نیست و باید فقط در شرایطی استفاده شود که تعداد زیادی Object مشابه واقعاً در حافظه وجود داشته باشد. <Cite refs={["turn0search0","turn0search2"]} />
آیا Flyweight در PHP همیشه باعث بهبود عملکرد میشود؟
خیر.
Flyweight یک ابزار بهینهسازی است و نباید بدون اندازهگیری استفاده شود.
قبل از پیادهسازی آن بهتر است موارد زیر بررسی شوند:
- تعداد Objectهای همزمان در حافظه چقدر است؟
- چه مقدار State میان Objectها تکرار میشود؟
- آیا مصرف حافظه واقعاً مشکل ایجاد کرده است؟
- آیا میتوان دادهها را با آرایه یا ساختار سادهتری نگهداری کرد؟
- هزینه ساخت و جستوجوی Flyweight چقدر است؟
- آیا پیچیدگی اضافه ارزش کاهش حافظه را دارد؟
اگر تعداد Objectها کم باشد، استفاده از Flyweight ممکن است فقط کد را پیچیدهتر کند.
تست Flyweight با PHPUnit
برای تست Flyweight میتوان بررسی کرد که Factory برای State مشترک یک Object یکسان برمیگرداند.
<?php
declare(strict_types=1);
use PHPUnit\Framework\TestCase;
final class ProductVariationFactoryTest extends TestCase
{
public function test_it_reuses_same_variation(): void
{
$factory = new ProductVariationFactory();
$first = $factory->get(
brand: 'Example Brand',
color: 'Black',
image: 'products/black-laptop.jpg'
);
$second = $factory->get(
brand: 'Example Brand',
color: 'Black',
image: 'products/black-laptop.jpg'
);
self::assertSame($first, $second);
self::assertSame(1, $factory->count());
}
public function test_it_creates_different_variations_for_different_states(): void
{
$factory = new ProductVariationFactory();
$black = $factory->get(
brand: 'Example Brand',
color: 'Black',
image: 'products/black-laptop.jpg'
);
$white = $factory->get(
brand: 'Example Brand',
color: 'White',
image: 'products/white-laptop.jpg'
);
self::assertNotSame($black, $white);
self::assertSame(2, $factory->count());
}
}
در تست اول، دو درخواست با State یکسان باید همان Object را برگردانند. در تست دوم، چون State متفاوت است، Factory باید دو Flyweight جداگانه ایجاد کند.
اشتباهات رایج در Flyweight Pattern
اشتباه اول: استفاده از Flyweight بدون مشکل حافظه
اگر پروژه شما تعداد کمی Object دارد، Flyweight احتمالاً ضروری نیست.
اشتباه دوم: قرار دادن State اختصاصی در Flyweight
قیمت، شناسه، موجودی و موقعیت هر نمونه نباید در Object مشترک قرار بگیرد.
اشتباه سوم: قابل تغییر بودن Flyweight
تغییر State مشترک میتواند روی چندین Context اثر بگذارد.
اشتباه چهارم: ساخت Key نامطمئن
اگر Key بهدرستی ساخته نشود، ممکن است دو State متفاوت یک Flyweight مشترک دریافت کنند.
اشتباه پنجم: نادیدهگرفتن نوع داده
برای ساخت Key بهتر است نوع دادهها مشخص و قابل پیشبینی باشند. استفاده از رشتهسازی ساده برای دادههایی که شامل جداکننده هستند ممکن است باعث تداخل Key شود.
اشتباه ششم: نگهداری بینهایت Flyweight در حافظه
Factory نیز میتواند به مرور زمان تعداد زیادی Object در خود نگهداری کند. در سیستمهای طولانیمدت باید ظرفیت، Expiration یا روش پاکسازی Pool بررسی شود.
اشتباه هفتم: استفاده از Flyweight به جای Cache
Cache برای ذخیره نتیجه محاسبات یا درخواستهاست؛ Flyweight برای اشتراکگذاری State میان Objectها طراحی شده است. این دو مفهوم ممکن است شبیه به نظر برسند، اما یکسان نیستند.
نمونه کامل Flyweight Pattern در PHP
<?php
declare(strict_types=1);
final class ProductVariation
{
public function __construct(
public readonly string $brand,
public readonly string $color,
public readonly string $image
) {
}
}
final class Product
{
public function __construct(
public readonly int $id,
public readonly float $price,
public readonly ProductVariation $variation
) {
}
public function summary(): string
{
return sprintf(
'#%d | %.2f | %s | %s',
$this->id,
$this->price,
$this->variation->brand,
$this->variation->color
);
}
}
final class ProductVariationFactory
{
/**
* @var array<string, ProductVariation>
*/
private array $pool = [];
public function get(
string $brand,
string $color,
string $image
): ProductVariation {
$key = hash(
'sha256',
json_encode([
'brand' => $brand,
'color' => $color,
'image' => $image,
], JSON_THROW_ON_ERROR)
);
if (!isset($this->pool[$key])) {
$this->pool[$key] = new ProductVariation(
brand: $brand,
color: $color,
image: $image
);
}
return $this->pool[$key];
}
public function count(): int
{
return count($this->pool);
}
}
$factory = new ProductVariationFactory();
$products = [];
for ($i = 1; $i <= 5; $i++) {
$products[] = new Product(
id: $i,
price: 50000000 + $i * 100000,
variation: $factory->get(
brand: 'Example Brand',
color: 'Black',
image: 'products/black-laptop.jpg'
)
);
}
foreach ($products as $product) {
echo $product->summary() . PHP_EOL;
}
echo "Shared variations: {$factory->count()}" . PHP_EOL;
خروجی نمونه:
#1 | 50100000.00 | Example Brand | Black
#2 | 50200000.00 | Example Brand | Black
#3 | 50300000.00 | Example Brand | Black
#4 | 50400000.00 | Example Brand | Black
#5 | 50500000.00 | Example Brand | Black
Shared variations: 1
در این نمونه، پنج محصول داریم، اما فقط یک ProductVariation ساخته شده است.
جمعبندی
Flyweight Pattern در PHP یک الگوی ساختاری برای کاهش مصرف حافظه از طریق اشتراکگذاری State مشترک میان چندین Object است.
در این الگو:
- Intrinsic State در Flyweight قرار میگیرد.
- Extrinsic State در Context نگهداری میشود.
- Flyweight Factory Objectهای مشترک را مدیریت میکند.
- Flyweight بهتر است Immutable باشد.
- Client به جای ساخت مستقیم Object، آن را از Factory دریافت میکند.
Flyweight برای سیستمهایی مناسب است که تعداد زیادی Object مشابه را بهصورت همزمان در حافظه نگهداری میکنند. با این حال، در پروژههای معمول PHP و Laravel نباید بدون بررسی مصرف حافظه از آن استفاده کرد. ابتدا باید مشخص شود که مشکل واقعی حافظه وجود دارد و اشتراکگذاری State میتواند آن را برطرف کند.
سوالات متداول
Flyweight Pattern در PHP چیست؟
Flyweight Pattern الگویی ساختاری است که اطلاعات مشترک میان چندین Object را در یک Object قابل اشتراک نگهداری میکند تا از تکرار دادهها و مصرف غیرضروری حافظه جلوگیری شود.
Intrinsic State چیست؟
Intrinsic State اطلاعات مشترک و معمولاً ثابت است که میان چندین Object استفاده میشود؛ مانند رنگ، تصویر، نوع محصول یا نام برند.
Extrinsic State چیست؟
Extrinsic State اطلاعات اختصاصی هر نمونه است؛ مانند شناسه، قیمت، موجودی، مختصات یا وضعیت لحظهای.
Flyweight Factory چه کاری انجام میدهد؟
Factory بررسی میکند Flyweight موردنظر قبلاً ساخته شده است یا خیر. اگر ساخته شده باشد همان Object را برمیگرداند و در غیر این صورت Object جدید ایجاد میکند.
آیا Flyweight با Singleton یکسان است؟
خیر. Singleton معمولاً برای داشتن یک نمونه از یک کلاس استفاده میشود، اما Flyweight میتواند چند نمونه با Stateهای مختلف داشته باشد و هدفش اشتراکگذاری دادههای مشترک است.
آیا Flyweight در Laravel کاربرد دارد؟
بله، اما فقط در شرایط خاص. برای دادههای مشترک محصولات، قالبهای پیام، تنظیمات ثابت یا تعداد زیادی Object مشابه میتوان از آن استفاده کرد؛ البته در بسیاری از موارد Cache، Service Container یا ساختارهای سادهتر انتخاب مناسبتری هستند.
آیا Flyweight همیشه مصرف حافظه را کاهش میدهد؟
خیر. میزان کاهش حافظه به تعداد Objectها، مقدار دادههای تکراری و نحوه پیادهسازی بستگی دارد. اگر Objectهای کمی وجود داشته باشند، Flyweight ممکن است فقط پیچیدگی بیشتری ایجاد کند.
مهمترین نکته در طراحی Flyweight چیست؟
باید State مشترک و اختصاصی بهدرستی از هم جدا شوند. همچنین Flyweight بهتر است Immutable باشد تا تغییر آن روی چندین Context اثر ناخواسته نگذارد. <Cite refs={["turn0search2","turn0search4"]} />





