ভিজিটর ডিজাইন প্যাটার্ন


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

  • কানেক্ট করা
  • ডিসকানেক্ট করা

আমরা জানি যে, অনেকগুলো অবজেক্ট এর যে সব কমন প্রপার্টি / কাজ আছে সেগুলোকে একটি কমন ইন্টারফেস/এবস্ট্রাক্ট class এ নিয়ে যাওয়া উচিত । সো মনে করুন কমন ইন্টারফেসটির নাম হচ্ছে IModem। তাহলে আমদের ইন্টারফেসটি দাঁড়াল এরকমঃ

public interfaceIModem
{
     void Connect();
     void Disconnect();
}

এখন তিন প্রকার মডেমের জন্য আমাদের তিনটি class যথাক্রমে Grameen, Teletalk এবং Zoom যারা প্রত্যকেই IModem ইন্টারফেসটিকে ইমপ্লিমেন্ট করবে । তাহলে আমরা class তিনটি লিখে ফেলি।

গ্রামীণ মডেমঃ

    public class Grameen : IModem
    {
        public void Connect()
        {
            Console.WriteLine("Grameen Modem Successfully connected");
        }
        public void Disconnect()
        {
            Console.WriteLine("Grameen Modem Successfully disconnected");
        }
    }

জুম মডেমঃ

    public class Zoom : IModem
    {
        public void Connect()
        {
            Console.WriteLine("Zoom Modem Successfully connected");
        }

        public void Disconnect()
        {
            Console.WriteLine("Zoom Modem Successfully disconnected");
        }
     }

টেলিটক মডেমঃ

    public class Teletalk : IModem
    {
        public void Connect()
        {
            Console.WriteLine("Teletalk Modem Successfully connected");
        }
        public void Disconnect()
        {
            Console.WriteLine("Teletalk Modem Successfully disconnected");
        }
    }

এখন মনে করুন ConfigureForUnix() নামে আমাদের নতুন একটি মেথড এর দরকার পড়ছে যেটা দিয়ে আমাদের এই মডেম গুলো Unix অপারেটিং এ কাজ করবে ।

ConfigureForUnix() মেথডের মধ্যে আলাদা আলাদা মডেম তাদের নিজস্ব ইমপ্লিমেন্টেশন লিখে রাখবে যাতে করে সবগুলো মডেম Unix অপারেটিং সিস্টেমে চলে।

তাহলে আমরা ConfigureForUnix() মেথডটি IModem ইন্টারফেসে নিয়ে যেতে পারি । তাহলে সবকয়টি মডেম ConfigureForUnix() ইউজ করে Unix অপারেটিং সিস্টেমে চলবে।

তাহলে আমাদের পরিবর্তিত ইন্টারফেসটি এরকম হবেঃ

   public interface IModem
    {
        void Connect();
        void Disconnect();
        void ConfigureForUnix();
    }

এবং আমাদের বাকি মডেম class গুলো এরকম দাঁড়াবেঃ

গ্রামীণ মডেমঃ

    public class Grameen : IModem
    {
        public void Connect()
        {
            Console.WriteLine("Grameen Modem Successfully connected");
        }
        public void Disconnect()
        {
            Console.WriteLine("Grameen Modem Successfully disconnected");
        }
        public void ConfigureForUnix()
        {
            Console.WriteLine("Configure Grameen Modem For Unix Operating System");
        }
    }

জুম মডেমঃ

    public class Zoom : IModem
    {
        public void Connect()
        {
            Console.WriteLine("Zoom Modem Successfully connected");
        }
        public void Disconnect()
        {
            Console.WriteLine("Zoom Modem Successfully disconnected");
        }
        public void ConfigureForUnix()
        {
            Console.WriteLine("Configure Zoom Modem For Unix Operating System");
        }
    }

এবং টেলিটক মডেমঃ

    public class Teletalk : IModem
    {
        public void Connect()
        {
            Console.WriteLine("Teletalk Modem Successfully connected");
        }
        public void Disconnect()
        {
            Console.WriteLine("Teletalk Modem Successfully disconnected");
        }
        public void ConfigureForUnix()
        {
            Console.WriteLine("Configure Teletalk Modem For Unix Operating System");
        }
    }

এখন ধরুন আমাদের ম্যাক অপারেটিং সিস্টেমের জন্য মডেম এর কনফিগারেশন লিখতে হবে । তাহলে আমাদের ইন্টারফেস এ ম্যাক কনফিগার করার জন্য আরোও একটি নতুন মেথড অ্যাড করতে হবে । এভাবে যতগুলো অপারেটিং সিস্টেম / ডিভাইস এর জন্য আমাদের মডেমগুলো করফিগার করতে হবে ততগুলো মেথড আমাদের ইন্টারফেসে অ্যাড করতে হবে।

তাহলে এভাবে চলতে থাকলে আমরা আমাদের IModem ইন্টারফেসটিকে কখনই ক্লোজ করতে পারবো না অর্থাৎ আমরা যখনই নতুন মেথড অ্যাড করতে যাব তখনই ইন্টারফেস এ মোডিফিকেকশন করতে হবে যা কিনা Open Close Principle (OCP) এর ভায়োলেশন ।

তাহলে আমরা এই সমস্যার সমাধান করতে পারি কিভাবে ? আমরা এই সমস্যার সমাধান করতে পারি ভিজিটর ডিজাইন প্যাটার্ন দিয়ে । ভিজিটর ডিজাইন প্যাটার্ন একটি টেকনিক ইউজ করে যেটার নাম হচ্ছে Dual Dispatch. এর সম্পর্কে হালকা ধারণার জন্যে পোষ্টের শেষে দেখুন

তাহলে চলুন Dual Dispatch টেকনিক ইউজ করে আমরা এই সমস্যাটার সমাধান করে ফেলি।

প্রথমে আমরা একটি ইন্টারফেস বানাবো যার নাম হচ্ছে IModemVisitor

আমাদের নতুন বানানো ইন্টারফেসটি দেখতে এরকমঃ

   public interface IModemVisitor
    {
        void Visit(Grameen grammenModem);
        void Visit(Teletalk teleTalkModem);
        void Visit(Zoom zoomModem);
    }

এখন আমাদের আগের IModem ইন্টারফেসটি সামান্য চেঞ্জ করে এরকম করা হলো যাতে করে এটি IModemVisitor ইন্টারফেসকে ব্যবহার করতে পারে ।

    public interface IModem
    {
        void Connect();
        void Disconnect();
        void Accept(IModemVisitor modemVisitor);
    }

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

অপারেটিং সিস্টেমের জন্য কনফিগার করবো । তাহলে আমাদের নতুন মডেম class গুলো হচ্ছে এরকমঃ

গ্রামীণ মডেমঃ কনফিগার ফর উইন্ডোজঃ

   public class Grameen : IModem
    {
        public void Connect()
        {
            Console.WriteLine("Grameen Modem Successfully connected");
        }

        public void Disconnect()
        {
            Console.WriteLine("Grameen Modem Successfully disconnected");
        }
        public void Accept(IModemVisitor modemVisitor)//Dual Dispatch
        {
            modemVisitor.Visit(this);
        }
        public void ConfigurationForWindows()
        {
            Console.WriteLine("Configuring Grameen modem for Windows Operating System");
        }

    }

জুম মডেম কনফিগার ফর ম্যাকঃ

  public class Zoom : IModem
    {
        public void Connect()
        {
            Console.WriteLine("Zoom Modem Successfully connected");
        }
        public void Disconnect()
        {
            Console.WriteLine("Zoom Modem Successfully disconnected");
        }
        public void Accept(IModemVisitor modemVisitor)
        {
            modemVisitor.Visit(this);
        }
        public void ConfigurationForMac()
        {
            Console.WriteLine("Configuring zoom modem for Mac Operating System");
        }
    }

এবং টেলিটক মডেম কনফিগার ফর ইউনিক্সঃ

    public class Teletalk : IModem
    {
        public void Connect()
        {
            Console.WriteLine("Teletalk Modem Successfully connected");
        }
        public void Disconnect()
        {
            Console.WriteLine("Teletalk Modem Successfully disconnected");
        }
        public void Accept(IModemVisitor modemVisitor)
        {
            modemVisitor.Visit(this);
        }
        public void ConfigurationForUnix()
        {
            Console.WriteLine("Configuring Teletalk modem for Unix Operating System");
        }

    }

All Operating System এর জন্য আমরা নতুন একটি class বানাবো যেটি আমাদের নতুন ইন্টারফেস IModemVisitor কে ইমপ্লিমেন্ট করবে এভাবেঃ

    public class AllModemConfigurator : IModemVisitor
    {
        public void Visit(Grameen grammenModem)
        {
            grammenModem.Connect();
            grammenModem.ConfigurationForWindows();
            grammenModem.Disconnect();
        }
        public void Visit(Teletalk teleTalkModem)
        {
            teleTalkModem.Connect();
            teleTalkModem.ConfigurationForUnix();
            teleTalkModem.Disconnect();
        }
        public void Visit(Zoom zoomModem)
        {
            zoomModem.Connect();
            zoomModem.ConfigurationForWMac();
            zoomModem.Disconnect();
        }
    }

তাহলে আমরা আমাদের ক্লায়েন্ট কোড এ মডেম ভিজিটরকে ইউজ করতে পারি এভাবেঃ

        public static void Main(string[] args)
        {
            IModemVisitor modemVisitor = new AllModemConfigurator();

            var modemList = new List<IModem>
            {
                new Grameen(),
                new Teletalk(),
                new Zoom()
            
            };
            foreach (var modem in modemList)
            {
                modem.Accept(modemVisitor);
            }
            Console.ReadLine();
        }

এখন নতুন কোনও অপারেটিং সিস্টেমের জন্য (যেমন এন্ড্রোয়েড)এবং নতুন কোনও মডেমের জন্য (যেমন এয়ারটেল) কনফিগারেশন লিখতে হলে আমাদের নিম্নলিখিত কাজ গুলো করতে হবেঃ

১।নতুন মডেমের class বানাতে হবে যেটি IModem ইন্টারফেসকে ইমপ্লিমেন্ট করবে

২)নতুন মডেমের class এর মধ্যে নতুন একটি মেথড বানিয়ে এর মধ্যে এন্ড্র্যেয়েডের জন্য কনফিগারেশন লিখতে হবে ।

৩)IModemVisitor ইন্টারফেসের Visit() মেথডের মধ্যে  আমাদের নতুন মডেমের অবজেক্ট এর রেফারেন্স পাস করে দিতে হবে ।

সবশেষে IModemVisitor দিয়ে একে কল করতে হবে।

তাহলে দেখা যাচ্ছে আমাদের ভিজিটর ডিজাইন প্যাটার্ন ব্যবহার করলে IModem ইন্টারফেসে কোনও রকম চেঞ্জ না করেই আমরা যে কোনও Concrete Class এ নতুন নতুন ফিচার অ্যাড করতে পারি । এটাই হচ্ছে ভিজিটর ডিজাইন প্যাটার্নের বৈশিষ্ট্য ।

Double Dispatch কিঃ

তো ডুয়েল ডিসপ্যাচ টা আসলে কি?  ডুয়েল ডিসপ্যাচে একটি অবজেক্ট (এখানে আমাদের ক্ষেত্রে Zoom,Teletalk,Grameen)Accept()  মেথডের মাধ্যমে (আমাদের এখানে Accept() মেথড ইন্টারফেস IModem এ ডিক্লেয়ার করা হয়েছে) একটি Visitor অবজেক্ট রিসিভ করে এবং Visitor অবজেক্ট এর Visit() মেথড কে কল করে ।(সকল Visitor অবজেক্ট যেমনAllModemConfigurator,IModemVisitor ইন্টারফেসকে ইমপ্লিমেন্ট করে)।

যেহেতু Visitor অবজেক্ট এর অনেকগুলো Visit মেথড আছে সেহেতু এই মেথডের ভেতর দিয়ে যে অবজেক্ট এর রেফারেন্স পাস করা হবে সে অবজেক্ট এর ফাংশনালিটি আমরা কল করতে পারবো ।

এখানে আমাদের দুইটি কল আছে (ডাবল ডিসপ্যাচ) যেটা সঠিক অবজেক্ট সিলেক্ট করে এবং সেই সঠিক অবজেক্ট এর জন্য এর সঠিক অপারেশনগুলো কল করে  । যেমন আমরা গ্রামীণ মডেমের জন্যে Unix Operating System এর কনফিগারেশন লিখেছি । সো Double Dispatch দিয়ে আমরা গ্রামীণ মডেম সিলেক্ট করেছি এবং এর জন্যে নির্দিষ্ট করে রাখা ফাংশনগুলো কল করতে পেরেছি । এই হচ্ছে মোটামুটিভাবে Double Dispatch ম্যাকানিজম ।

হ্যাপি কোডিং 🙂

One thought on “ভিজিটর ডিজাইন প্যাটার্ন

Leave a comment