الگوی Flyweight

تصور کنید، شما مسئول طراحی یک برنامه هستید که قرار است برای هر کارمند یک سازمان، کارت ویزیتی مانند شکل زیر چاپ کند. سازمان مورد نظر، یک سازمان بسیار بزرگ با چند هزار کارمند می باشد.

نام و نام خانوادگی

سمت

نام شرکت

آدرس

اواین طراحی که به ذهن می تواند خطور کند، یک طراحی بسیار ساده است. یک کلاس به نام کارت ویزیت تعریف می کنیم و صفاتی را که در کارت قرار دارند، به کلاس منتقل می کنیم و یک متد چاپ هم برای چاپ کارت تعریف می کنیم.

visitCard

Name

Title

Company

Address

print

در این صورت شما باید به ازاء هر کارمند یک نمونه از کلاس visitCard ایجاد کند، یعنی شما باید چند هزار شی visitCard ایجاد کند. و این می تواند منابع زیادی از سیستم را مصرف کند. ولی شما با توجه به ساختار کارت متوجه می شود که، نام شرکت و آدرس برای تمام افراد یکی است. با این آگاهی، آیا می خواهید تغییری در طراحی خود انجام بدهید یا نه؟

یا شما مسئول طراحی یک برنامه پردازش متن هستید. شکل زیر، می تواند یک نمودار کلاس ساده شده برای این برنامه باشد.

هر نمونه از کلاس Docchar نماینگر یک کاراگتر در سند است. برای تغییر فونت یک کاراگتر می توانیم متد SetFont از شی Docchar فراخوانی کنیم. اگر فونت یک کاراگتر مشخص نشده باشد، از فونت container خود استفاده خواهد کرد.

یک سند نمونه از این برنامه را با طراحی بالا در نظر بگیرید،  یک سند که شامل چندین صفحه است، هر  صفحه شامل چندین شی پارگراف خواهد بود، و هر پارگراف شامل چندین شی LineOfTextad   خواهد بود و آن نیز شامل صد ها شی DocChar خواهد بود، یعنی در یک سند چند صفحه ای ممکن است هزار ها شی  DocChar داشته باشیم که، حافظه زیادی را از سیستم مصرف خواهد کرد. شما برای کاهش مصرف حافظه، طراحی خود را به چه صورت تغییر می دهید؟

یک راه حل کاندید و خوب برای حل هر دو مسئله بالا، الگوی Flyweight است. که به بررسی آن خواهیم پرداخت. مشکل ما در هر دو مسئله بالا، تولید نمونه های بیش از حد از یک کلاس بود که منجر به مصرف زیاد منابع می شد. یک شی شامل ۲ نوع اطلاعات است:

۱-       اطلاعات داخلی (Intrinsic Information) : این نوع اطلاعات، اطلاعاتی هستند که برای تمام نمونه های یک کلاس ثابت است. برای مثال، نام شرکت و آدرس در مثال اول برای تمام کارمندان ثابت است.

۲-       اطلاعات خارجی (Extrinsic Information) : این نوع اطلاعات، اطلاعاتی هستند که از نمونه ای به نمونه ای دیگر فرق می کند، یعنی اشیاء را از همدیگر متمایز می سازد. برای مثال، نام و سمت کارمند در مثال اول.

پیشنهاد الگوی Flyweight این است که،  اطلاعات خارجی را، به خارج از کلاس منتقل کنیم و این اطلاعات را به صورت پارامتر های ورودی متدها دریافت کنیم، و تعداد نمونه ها را با به اشتراک گذاری آنها کاهش دهیم. نمودار کلاس این الگو بصورت زیر است.

در نمودار بالا هر کدام از،ConcreteFlyweight ها نمونه های به اشتراک گذاری یک کلاس هستند. چون اشیاء به اشتراک گذاشته شده اند، Client ها نباید بطور مستقیم نمونه ای از آنرا ایجاد کنند. برای حل این مشکل، کلاس  FlyweightFactory را ایجاد می کنیم. این کلاس باید بداند که آیا نمونه ای از یک کلاس ایجاد شده است یا نه. برای این کار، لیستی از اشیاء ایجاد شده را نگهداری می کنیم  که این اشیاء از کلاس های مختلف توسط یک صفت کلید از هم متمایز می شوند. در مثال ۲ ما برای حل مشکل خود برای هر کاراکتر، یک کلاس،تعریف می کنیم. کلید هر کدام از کلاس ها همان، کاراکتری است که نمایش خواهند داد. برای نمونه کلاس زیر را در نظر بگیرید، کلید هر کلاس را در  یک Hashtable ذخیره می کنیم، و وقتی که Client بخواهد نمونه ای از کلاس مورد نظرش را بسازد، این کلاس بررسی می کند که آیا این کلید در Hashtable وجود دارد یا نه. اگر وجو نداشته باشد، نمونه ای از کلاس مورد نظر ایجاد می کند، در غیر اینصورت  مرجعی (reference) به آنرا برگشت می دهد.

class CharacterFactory

    {

        private Hashtable characters = new Hashtable();

 

        public Character GetCharacter(char key)

        {

            Character character = characters[key] as Character;

            if (character == null)

            {

                switch (key)

                {

                    case ‘A’: character = new CharacterA(); break;

                    case ‘B’: character = new CharacterB(); break;

                    //…

                    case ‘Z’: character = new CharacterZ(); break;

                }

                characters.Add(key, character);

            }

            return character;

        }

    }