সিঙ্গেলটন প্যাটার্ন (Singleton Pattern)


আপনারা জেনে খুশি হবেন যে Singleton Pattern হচ্ছে সৃষ্টিকর্তার দুনিয়াতে যত রকমের ডিজাইন প্যাটার্ন  আছে এর মধ্যে  Class Diagram এর ভিত্তিতে বিবেচনা করলে এটিই সবচেয়ে সহজ ডিজাইন প্যাটার্ন । Diagram এ এর মাত্র একটি class ।

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

তবে চলুন জেনে নিই এই ডিজাইন প্যাটার্নের খুটিনাটি ।

একদিন আমার ইন্সটিটিউট এর এক জুনিয়র আমার কাছে আসলো Singleton Pattern বুঝতে ।সে সবে মাত্র OOP এর কোর্স শুরু করেছে ।

নতুন অবজেক্ট বানানো , এক্সেস মোডিফায়ার যেমন private, public,protected এগুলো সম্পর্কে হাল্কাপাতলা ধারণা আছে তার ।

অনেক বার Null Reference exception খেয়ে সে Null কি জিনিস বুঝেছে ।

সে আমাকে জিজ্ঞেস করলো “ভাই এই প্যাটার্ন কি কাজে লাগে এইটা আগে বলেন“ ।

আমি বললাম “দেখ আমাদের এপ্লিকেশনের লাইফ সাইকেলে এমন কিছু অবজেক্টের দরকার পরে যারা পুরো এপ্লিকেশন জুড়ে একটাই থাকবে। মানে পুরা এপ্লিকেশন এ একটা মাত্র অবজেক্ট থাকবে  এবং ঐ একটা অবজেক্ট কেই সবাই এক্সেস করতে পারবে । যেমন মনে কর তুই যে উইন্ডোজ ইউজ করিস এই উইন্ডোজ এর Registry Settings  যদি একটা class হিসেবে চিন্তা করিস এবং এটি যদি অনেক রিসোর্স ধারণ করে তাহলে যারা উইন্ডোজ ডেভেলপার  মাইক্রোসফটে তাদের সবাইকে এই class টাই এক্সেস করতে হবে । এই class টা যেহেতু অনেক রিসোর্স ধরে রাখে সেহেতু যদি ডেভেলপাররা তাদের কোডে ইচ্ছে মত RegistrySettings class এর অবজেক্ট বানানো শুরু করে তাহলে অনেক অনেক অবজেক্ট তৈরি হচ্ছে যারা অনেক অনেক রিসোর্স খেয়ে ফেলছে । পারফরমেন্স খারাপ এবং মাইক্রোসফটের ব্যবসায় লাল বাতি । আবার সব ডেভেলপারকেই একই RegistrySettings নিয়ে কাজ করতে হবে কেননা এটি একটু চেঞ্জ করলেই সিস্টেম ক্রাশ করতে পারে । সো যে RegistrySettings class বানিয়েছে তাকে class টা এমন ভাবে ডিজাইন করতে হবে যাতে করে সবাই একটি মাত্র অবজেক্ট পায় পুরা এপ্লিকেশন জুড়ে । কেউ যাতে এর অবজেক্ট বানাতেই না পারে“

জুনিয়রঃ “সবই তো বুঝলাম ভাই কিন্তু আপনে এইডা কি কইলেন। কেউ যাতে এর অবজেক্ট না বানাইতে পারে । এইডা কোনও কথা হইলো ?? “

আমিঃ হুম এইটাই কথা । আচ্ছা বল তো তুই অবজেক্ট বানাস কিভাবে ??

জুনিয়রঃ যেমন ধরেন class এর নাম MyClass হইলে এর অবজেক্ট বানামু new MyClass() কইরা ।

আমিঃ হুম ঠিক আছে । এখন বল তো আমি যদি এর Constructor প্রাইভেট করে দিই তাহলে কেউ অবজেক্ট বানাতে পারবে ??

জুনিয়রঃ (মুখ ফ্যাকাসে করে ) না ভাই পারবো না 😦 তাইলে আমরা এই class এর একমাত্র অবজেক্ট বানামু ক্যামনে । যেইডা অন্য কেউ বাইরে থাইকা পাবে ??

আমিঃ দেখ , আমি তোকে বলেছি কেউ new করে সরাসরি অবজেক্ট বানাতে পারবেনা । কিন্তু আমরা একটা মেথড বানাতে পারি যেটি কিনা MyClass এর অবজেক্ট রিটার্ন করবে ।

জুনিয়রঃ হ বুইজা ফেলছি ভাই । তয় এই মেথডটারে Static হইতে হইবো । আমাগো স্যার পড়াইছে যে যদি আমরা কোনও class এর অবজেক্ট না বানাইয়া এর কোনও মেথড অথবা ভেরিয়েবল এক্সেস করতে চাই চাইলে ঐ মেথড অথবা ভেরিয়েবল রে Static হইতে হইবো ।

আমিঃ বাহ !! বেশ ভালো শিখেছিস তো । তো এবার কোডটা লিখে ফেল তো দেখি আমরা এতক্ষণ কি শিখলাম । আর class টার ভালো একটা নাম দিস। জুনিয়র কোড লিখলো এইভাবেঃ

    public class Singleton
    {
        private Singleton() { }
        public static Singleton CreateInstance()
        {
            return new Singleton();
        }
    }

আমিঃ ঠিক আছে কিন্তু তুই এমনভাবে কোডটা মোডিফাই কর যাতে করে শিওর হওয়া যায় যে শুধুমাত্র একবারই এই class এর অবজেক্ট তৈরি হবে । তুই চেক করতে পারিস অবজেক্টটা নাল আছে কিনা । নাল হলে অবজেক্ট বানিয়ে রিটার্ন করতে পারিস , আর নাল না হলে অবজেক্টটাকে এমনিতেই রিটার্ন করে দিতে পারিস। বুঝতে পেরেছিস??   জুনিয়র মাথা ঝাকিয়ে তার কোড মোডিফিকেশন করলো এই ভাবেঃ

public class Singleton
    {
        private static Singleton uniqueInstance;
        private Singleton() { }
        public static Singleton CreateInstance()
        {
            if (uniqueInstance == null)
            {
                uniqueInstance = new Singleton();
            }
            return uniqueInstance;
        }
    }

আমি বললাম ঠিক আছে এইবার । আমি বললাম এইবার ভালো করে শোন । এখানে একটা সমস্যা আছে ।

জুনিয়রঃ কোড তো করলাম । আবার কি সমস্যা ভাই ??:/

আমিঃ এই কোড ঠিক আছে কিন্তু এইটা Multithreaded Environment এ কাজ করবে না । মনে কর একটা প্রিন্টার আছে Lan Connected  । একই Lan এর ভেতরে যারা পিসিতে কাজ করে তারা তাদের পিসি থেকে কমান্ড দেয় এবং প্রিন্টের কাজ গুলো করে । মনে কর একই সময়ে দুই জন লোক প্রিন্টের কমান্ড দিলো । এখন প্রিন্টার প্রিন্ট করবে কিভাবে ?? দুই জনই তো একই সময়ে কমান্ড দিয়েছে প্রিন্টের জন্য । সো Printer Multithreaded না হলে কিন্তু এইটা  ক্রাশ করতো । ঠিক একই ভাবে মনে কর Multithreaded সিস্টেমে একই সময়ে দুইজন Singleton এর অবজেক্ট এক্সেস করতে চাইলো তারা Singleton class এর মধ্যে if(uniqueInstance==null) দেখতে পেলো ফলে তারা প্রত্যকের জন্য একটি করে অবজেক্ট এক্সেস করলো । তাহলে আমাদের এই ডিজাইন Singleton এর মুল থিমটাকেই ভায়োলেট করলো ।

জুনিয়রঃ তাহলে এইটা সল্ভ করুম ক্যাম্নে  ভাই??

আমিঃ lock ইউজ করা আমরা যেহেতু ডট নেটে কোড লিখছি । আমরা জাভাতে কোড লিখলে আমাদের Syncronize ইউজ করা লাগতো। জুনিয়রঃ ভাই আমি এগুলো পারি না । আপনি লেখেন । আমি lock ইমপ্লিমেন্ট করলাম এইভাবেঃ

public class Singleton
    {
        private static Singleton uniqueInstance;
        private static object _lock = new object();
        private Singleton() { }
        public static Singleton CreateInstance()
        {
            lock (_lock)
            {
                if (uniqueInstance == null)
                {
                    uniqueInstance = new Singleton();
                }
            }
            return uniqueInstance;
        }
    }

জুনিয়রঃ ভাই এইটা কি করলেন কিছু বুঝি নাই । বুঝাইয়া দেন ।

আমিঃ এইখানে lock ইউজ করে আমি দুইটা Thread কেই ফরস করছি যে তারা যেনো একই সাথে uniqueInstance==null চেক না করতে পারে। একটা চেক করা শেষ করলে আরেকটা ঢুকবে চেক করার জন্য । দুইজন একসাথে নাল চেক না করে তাহলেই তো আমাদের আর সমস্যা থাকছে না ।একজন এসে নাল চেক করে নাল পেলে নতুন অবজেক্ট বানিয়ে রিটার্ন করবে আরেক জন এসে নাল চেক করে দেখবে যে অবজেক্ট বানানো আছে । তাহলে সে বানানো অবজেক্টটাই পাবে ।

জুনিয়রঃ বাহ বেশ মজার তো । তাইলে তো এখন শেষ । চলেন ভাই চা খেয়ে আসি ।

আমিঃ না এইখানে আরও কাহিনী আছে। একটু ওয়েট কর।

জুনিয়রঃ (বিরক্ত হয়ে) হ ভাই , কইয়া ফালান ।

আমিঃ দেখ এই lock জিনিসটা  খুব যে ভালো তা কিন্তু না । এইটা অনেক বাজে পারফরমেন্স দিবে । তোর এপ্লিকেশনের পারফরমেন্স নিয়ে যদি মাথা ব্যথা না থাকে তখন এই কোড ইউজ করলে সমস্যা নাই । কিন্তু পারফরমেন্স নিয়ে মাথা ব্যাথা থাকলে তোকে  Eagerly Created Instance ইউজ করতে হবে । খুবই সিম্পলঃ

public class Singleton
    {
        private static readonly Singleton UniqueInstance = new Singleton();//eagerly created instance
        private Singleton() { }
        public static Singleton CreateInstance()
        {
            return UniqueInstance;
        }
    }

আমাদের আর lock ইউজ করা লাগলো না । এইভাবে কোড করলে .Net Runtime Singleton class টা লোড হওয়ার সাথে সাথে এর Instance বানিয়ে রেখে দিবে । যে কেউ এক্সেস করতে চাইলে তাকে এই Instance টা দিয়ে দিবে ।এই এপ্রোচ Thread Safe কিন্তু একটা সমস্যা হতে পারে যে , মনে কর এই class টাকে অনেকক্ষণ কেউ এক্সেস করলো না । এতক্ষণ সময় ধরে যে মেমরির বেশ বড় একটা অংশ দখল করে বসে থাকলো । এটা আসলে উচিত না অনুচিত এটা তোর এপ্লিকেশনের উপর ডিপেন্ড করবে ।

সবশেষে আরেকটা সলুশ্যনের কথা বলেই চা খেতে যাবো আমরা । জুনিয়র রাজি হলো শেষবারের মত।

আমরা lock ইমপ্লিমেন্ট করেছিলাম কিভাবে ঐখানে সামান্য একটু মোডিফিকেশন করলেই আমরা বেটার রেজাল্ট পেতে পারি । এই এপ্রোচের নাম হচ্ছে Double Checked lock . এই এপ্রোচে আমরা প্রথমে চেক করি যে আমাদের অবজেক্ট আগে বানানো হয়েছে কিনা । যদি না হয়ে থাকে তাহলে আমরা lock block এ ঢুকি । lock block এ আবার আমরা চেক করি অবজেক্ট এখনও নাল কিনা । নাল হলে আমরা নতুন অবজেক্ট বানিয়ে রিটার্ন করি । তাহলে আমাদের কোড হচ্ছে এ রকমঃ

public class Singleton
    {
        private volatile static Singleton uniqueInstance;
        private static readonly object _lock = new object();
        private Singleton() { }
        public static Singleton CreateInstance()
        {
            if (uniqueInstance == null)//double checked lock
            {
                lock (_lock)
                {
                    if (uniqueInstance == null)
                    {
                        uniqueInstance = new Singleton();
                    }
                }
            }
            return uniqueInstance;
        }
    }

এই Double Checked lock Approach পারফরমেন্স ইস্যু এবং Eagerly Created Instance এর ঝামেলা দূর করে ।

জুনিয়রঃ ভাই মাফ চাই চলেন চা খামু  :/ এতক্ষণ যে পেইন দিলেন এর জন্য চায়ের বিল আপনে দিবেন । তবে ঘটনা গুলান বুঝছি কিছু । যা যা কইলেন এতক্ষণ ।

আমিঃ চল চা খেয়ে আসি ,দেখি কত চা খেতে পারিস তুই ।

ছোটভাইঃ চলেন ভাই 😛

এই ছিলো Singleton Pattern এর ক খ গ ঘ । সিম্পল Class Design এবং সিম্পল ইমপ্লিমেন্টেশন হলেও এপ্লিকেশনে এর ব্যবহার খুব ভেবেচিন্তে করতে হয় আমাদের ।

(সমাপ্ত )

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 )

w

Connecting to %s