ফ্লাইওয়েট প্যাটার্ন (Flyweight Pattern)


আমি যখন ক্লাস থ্রি এ পরতাম তখন আমাদের বাসায় প্রথম সাদাকালো টিভি আসে ।

ঘট ঘট করে চ্যানেল চেঞ্জ করা লাগতো , এন্টেনা ঘুরিয়ে ফিরিয়ে ছবি ক্লিয়ার করা লাগতো । যে এন্টেনা ঘুরাতে যেতো সে মাঝে মাঝে চিল্লায়ে উঠতো “হইছে ………………………??”

আমরা উত্তর দিতাম “না আ আ আ …………………হয় নাই , আরোও ঘুরান । “ সে এক এলাহি ব্যপার স্যাপার ছিলো ।

টিভি কেনার আগে অনেক অনুনয় বিনয় করে অনুমতি নিয়ে অনেক দূরে বন্ধুর বাসায় গিয়ে বিটিভির শুক্রবারের পূর্ণদৈর্ঘ্য বাংলা ছায়াছবি দেখতে হত ।

একবার বাংলা ছায়াছবি “দিপু নাম্বার টু” দেখে বাড়ি ফিরতে সন্ধ্যা পার হয়ে যাওয়ার জন্য ছোটমামা আমাকে বালতির পানিতে মাথা চুবিয়ে রেখেছিল।

তো তখন চ্যানেল দেখতে পেতাম দুইটা । একটা লিজেন্ডারী বিটিভি আর একটা দূরদর্শন ।

দূরদর্শনে প্রতি রবিবার হিন্দু ধর্মালম্বিদের দেব দেবীদের নিয়ে অনুষ্ঠান দেখাতো ।

দেবদেবীদের অনুসারী সন্নাসী দের সাথে অসুরদের যুদ্ধ । আকাশ বাতাস কাঁপিয়ে ঢাল তলোয়ার নিয়ে লক্ষ লক্ষ অসুরদের সাথে লক্ষ লক্ষ সন্ন্যাসীদের যুদ্ধ হত ।

তো আসল কথায় আসি । বর্তমান সময়ে অনেক ভারতীয় প্রোগ্রামাররা স্মার্টফোন গুলোর জন্য অনেক অনেক গেম তৈরী করে আসছে ।   স্মার্টফোন এর মেমরি সাধারন পিসি গুলোর তুলনায় অনেক কম থাকে । তো একটা গেমে লক্ষ লক্ষ সৈন্য দরকার হয় । এখানে লক্ষ্যনীয় ব্যপার হচ্ছে অসুর হোক বা সন্ন্যাসী হোক প্রোগ্রামার এর কাছে সবাই এক একটি অবজেক্ট ছাড়া আর কিছুই না ।

এখন ১ লক্ষ অসুর + ১ লক্ষ সন্যাসী = ২ লক্ষ সৈন্যের অবজেক্ট তৈরী করলে ঐ গেম আর স্মার্টফোনে খেলা লাগবে না । সুপার কম্পিউটারে খেলা লাগবে 😛

এখন এই ব্যপার গুলো আমরা কোডের মাধ্যমে দেখে আসি চলুন।

যেহেতু অসুর এবং সন্ন্যাসী উভয়েই গেমের সৈন্য সেহেতু তাদের কমন কিছু প্রপার্টি থাকবে ।

যে প্রপারটি গুলো আমরা বাইরে থেকে চেঞ্জ করতে পারি না অথবা করতে পারি না সেগুলোকে বলা হয় intrinsic property. যেমন একটি সৈন্য তৈরি করার সময় এর পাওয়ার কত হবে তা বলে দিতে হয় । পরে আর আমরা এটা চেঞ্জ করতে পারি না । পাওয়ার শেষ হলে সৈন্য মারা যাবে ।

আবার যে প্রপার্টি গুলো বাইরে থেকে চেঞ্জ করা যাবে / করতে হবে সেগুলোকে বলা হয় Extrinsic property.

যেমন একটা সৈন্য বানানোর পর আমাদের এই সৈন্যটাকে মুভ করাতে হয় বিভিন্ন কন্ডিশনের উপর ভিত্তি করে । এটা আমাদের রানটাইমে ডিশিশন নিতে হয় । তো সৈন্যদের জন্য একটা কমন ইন্টারফেস বানাই ISoldier নামে:

    public interface ISoldier
    {
        int HealthStatus { get; set; }//intrinsic property
        void Move(int x1, int y1, int x2, int y2);//coordinates are extrinsic
    }

এখন আমাদের সৈন্য হচ্ছে দুই প্রকার একটা হচ্ছে অসুর এবং সন্ন্যাসী । আমরা এখন এদের class বানাবো যারা উভয়েই ISoldier কে ইমপ্লিমেন্ট করবে । আমরা class ডিজাইনটা এমন ভাবে করবো যাতে করে এই class এর কয়টি অবজেক্ট তৈরি হবে তা আমরা দেখতে পারি: আমাদের Asur class টি এই রকম:

public class Asur : ISoldier
    {
        public int HealthStatus { get; set; }
        public static int Objectcounter = 0;
        public Asur(int healthstatus)
        {
            HealthStatus = healthstatus;
            ++Objectcounter;
        }
        public void Move(int x1, int y1, int x2, int y2)
        {
            Console.WriteLine("Asur soldier is moving from ({0},{1}) to ({2},{3})", x1, y1, x2, y2);
        }
    }

এবং আমাদের Sonnasi class টি এই রকমঃ

public class Sonnasi : ISoldier
    {
        public int HealthStatus { get; set; }
        public static int ObjectCounter = 0;
        public Sonnasi(int healthStatus)
        {
            HealthStatus = healthStatus;
            ObjectCounter++;
        }
        public void Move(int x1, int y1, int x2, int y2)
        {
            Console.WriteLine("Sonnasi soldier is moving from ({0},{1}) to ({2},{3})", x1, y1, x2, y2);
        }
    }

এখন আমাদের ClientCode এ উদাহরন স্বরূপ উভয় টাইপের সৈন্যের জন্য ১০০ টি করে অবেজক্ট বানালে দেখা যাবে যে কনসোলে উভয়েরই ১০০ টি করে অবজেক্ট তৈরি হয়েছেঃ আমাদের ক্লায়েন্ট কোড এরকমঃ

public class Program
    {
        public static void Main(string[] args)
        {
            ISoldier soldier;
            for (int i = 0; i < 100; i++)
            {
                soldier = new Sonnasi(100);

            } Console.WriteLine(Sonnasi.ObjectCounter);
            for (int i = 0; i < 100; i++)
            {
                soldier = new Asur(200);
            }
            Console.WriteLine(Asur.Objectcounter);

            Console.ReadLine();
        }
    }

তাহলে এর সল্যুশন কেমন হবে ??

চলুন আমরা একটি ফ্যাক্টরি বানাই যেখানে একটি ভচ থাকবে । ভচের কাছে গিয়ে যে কোন এক টাইপের অবজেক্ট চাইব  আমরা । ভচের আগে চেক করবে তার কাছে ঐ টাইপের অবজেক্ট আছে কিনা । না থাকলে সে ফ্যাক্টরি থেকে বানিয়ে দিবে এবং এর পরে আবার কেউ যদি তার কাছে ঐ একই টাইপের অবজেক্ট নিতে আসে সে চেক করে তার সৈন্য ভান্ডার থেকে আগের অবজেক্ট টাই দিয়ে দিবে নতুন অবজেক্ট না বানিয়েই ।

চলুন আমরা কোড এ দেখে আসি ফ্যাক্টরির  ইমপ্লিমেন্টেশন । এর আগে দুই প্রকার সৈন্যের জন্য

আমরা একটা enum বানিয়ে নিই ।

public enum SoldierType
    {
        ASUR,
        SONNASI
    }

আর ফ্যাক্টরির ইমপ্লিমেন্টেশন টা এরকমঃ

public class SoldierFactory
    {
        private static readonly Dictionary<Enum, ISoldier> SoldierContainer = new Dictionary<Enum, ISoldier>();
        public static ISoldier GetSoldier(SoldierType soldierType)
        {
            ISoldier soldier = null;

            if (SoldierType.ASUR == soldierType)
            {
                if (!SoldierContainer.ContainsKey(soldierType))
                {
                    soldier = new Asur(100);
                    SoldierContainer.Add(soldierType, soldier);
                }
                soldier = SoldierContainer[soldierType];
            }
            else if (SoldierType.SONNASI == soldierType)
            {
                if (!SoldierContainer.ContainsKey(soldierType))
                {
                    soldier = new Sonnasi(200);
                    SoldierContainer.Add(soldierType, soldier);
                }
                soldier = SoldierContainer[soldierType];
            }
            return soldier;
        }
    }

এখানে আমরা যা করেছি তা হচ্ছে প্রথমে একটা ডিকশনারী নিয়েছি যেখানে সৈন্যের একটা টাইপ থাকবে এবং আমাদের ইন্টারফেসটা থাকবে ।

একটা স্ট্যাটিক মেথড বানিয়েছি যেটা ISoldier রিটার্ন করবে ।

তারপর আমরা চেক করেছি আমরা কি টাইপের সৈন্য চাই অসুর না সন্যাসী ।

অসুর হলে আমরা প্রথমে চেক করেছি ডিকশনারিতে এই টাইপের অবজেক্ট আছে কিনা ।

না থাকলে আমরা অসুরের জন্য অবজেক্ট বানিয়েছি এবং ডিকশনারীতে ঢুকিয়েছি যেনো পরের বার কেউ অসুর টাইপের সৈন্য চাইলে আমাদের নতুন অবজেক্ট না বানিয়ে এই ডিকশনারী থেকেই রিটার্ন করতে পারি ।

সবশেষে আমরা ডিকশনারী থেকে অবজেক্টটা নিয়ে রিটার্ন করেছি ।

একই কাজ আমরা সন্ন্যাসী টাইপের অবজেক্টের জন্যও করেছি ।

এখন আমাদের ClientCode টা দেখে আসিঃ

public class Program
    {
        public static void Main(string[] args)
        {
            ISoldier soldier;
            for (int i = 0; i < 100; i++)
            {
                soldier = SoldierFactory.GetSoldier(SoldierType.SONNASI);

            }
            Console.WriteLine(Sonnasi.ObjectCounter);
            for (int i = 0; i < 100; i++)
            {
                soldier = SoldierFactory.GetSoldier(SoldierType.ASUR);
            }
            Console.WriteLine(Asur.Objectcounter);

            Console.ReadLine();
        }
    }

প্রোগ্রামটি চালালে দেখা যাবে যে অসুর এবং সন্যাসী উভয়েরই মাত্র ১ টি করে মোট দুটি অবজেক্ট তৈরী হয়েছে যদিও আমরা ১০০ বার করে মোট ২০০ টি অবজেক্ট বানাতে চেয়েছি ।

এভাবে আমাদের এপ্লিকেশনে অনেক অনেক অবজেক্ট দরকার হলে FlyWeight Pattern ইউজ করে কমন প্রপার্টিগুলো শেয়ারিং এর মাধ্যমে অবজেক্ট বানিয়ে মেমরী সেভ করতে পারি ।

সমাপ্ত 🙂

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s