ষ্টেট ডিজাইন প্যাটার্ন


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

তিনি ছিলেন একাধারে গণিতবিদ , যুক্তিবিদ এবং ক্রিপ্টোবিশেষজ্ঞ । কম্পিউটার বিজ্ঞানে তার অসামান্য অবদান হচ্ছে টুরিং মেশিন । তিনি ১৯৩৬ সালে একটা হাইপোথেটিকাল মেশিন ডিজাইন করেন যেটা অ্যালগরীদম সিমুলেট করতে পারে ।

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

ছবিঃ অ্যালান টুরিং

টুরিং মেশিন যেভাবে কাজ করেঃ

টুরিং মেশিনে অনেকগুলো স্টেট থাকে। প্রতিটা স্টেট থেকে কোন স্টেট যাওয়া যায় সেটা নির্ভর করে ওই প্রবলেমের “ট্রানজিশন ডায়াগ্রাম” এর উপর। সহজ কথায় ডায়াগ্রামে বলা থাকে কোন ইনপুটের জন্য কোন স্টেট থেকে কোন স্টেটে যেতে হবে সেটা। কম্পিউটার বিজ্ঞানের শিক্ষার্থীরা “থিওরি অফ কম্পিউটিং” অথবা “কম্পাইলার ডিজাইন” এ অটোমাটা (Automata) বিষয়টি পড়ে থাকলে বুঝতে সুবিধা হবে ।                                                 

নিচের ছবিটি বিষয়টি বুঝতে সাহায্য করবে আশাকরিঃ


চিত্রঃ ষ্টেট ট্রানজিশন ডায়াগ্রাম

অনেক কথা বলে ফেললাম । এখন আসল কথায় আসা যাক । আমরা যে টুরিং মেশিনের কথা বললাম , এই মেশিনের আচরন (মানে এটি যেভাবে কাজ করে ) কিন্তু খুব ভালোভাবে ষ্টেট ডিজাইন প্যাটার্ন দিয়ে করে ফেলা যায় ।

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

এদের চেহারা একই হলেও এরা আলাদা ভাবে সম্পূর্ণ ভিন্ন দুটি সফটওয়্যার ডিজাইন প্রবলেম সল্ভ করে।তাহলে চলুন আমরা অনেক সহজ একটি উদাহরণের সাহায্যে স্টেট ডিজাইন প্যাটার্ন ইমপ্লিমেন্ট করে ফেলি।

উদাহরণঃ

সারাদিন কাজকর্ম শেষে আমরা সবাই যে যার বাসা/মেস/হোস্টেল এ ফিরি । ফিরেই আমরা যে জিনিসটি সবার আগে দেখি সেটা হচ্ছে বাসার গেট 😀 । আমরা কখনও গেট খোলা অবস্থায় দেখি , কখনও বন্ধ অবস্থায় দেখি, কখনোবা তালা বদ্ধ অবস্থায় দেখি ।

তাহলে আমরা গেট/দরোজা’র তিনটি স্টেট/অবস্থা দেখতে পাই । এই স্টেটগুলো আমরা টুকে নিই

  1. Open
  2. Closed
  3. Locked

এখন দারোয়ান মামারা এই দরজা/গেট এর উপর সারাদিন/সারারাত কি নির্যাতন চালায় মানে এগুলোর উপর কি কাজ/একশন করে তা টুকে নিইঃ

  1. UnlockGate
  2. LockGate
  3. OpenGate
  4. CloseGate

আমরা গেট এর স্টেট/অবস্থা এবং একশন গুলো পেয়ে গেছি , এখন আমরা ঝটপট কোডে চলে যাই ।আমরা Gate নামে একটি Class বানাবো এবং এর স্টেটগুলো ভেরিয়েবল হিসেবে রেখে দিব।

সকালে উঠে অফিসে যাওয়ার সময় যেহেতু আমরা বাসার গেট খোলা দেখি এজন্য CurrentState ভ্যারিয়েবলে আমরা OpenState টি রেখে দিই । এই CurrentState আমাদের সব সময় Gate এর কারেন্ট অবস্থা সম্পর্কে জানাবে ।

সো আমাদের Class টী দেখতে এরকমঃ

    public class Gate
    {
        private const int Opened = 1;
        private const int Closed = 2;
        private const int Locked = 3;
        private const int Unlocked = 4;
        public int CurrentState = Opened;
    }

আমরা এর আগে যে একশন গুলো পেয়েছিলাম সেগুলো আমাদের এই Class এ মেথড হিসেবে ব্যবহার করবো এভাবেঃ

মেথড ১: OpenGate()

       public void OpenGate()
        {
            if (CurrentState == Opened)
            {
                Console.WriteLine("The gate is already open....");
            }
            else if (CurrentState == Closed)
            {
                CurrentState = Opened;
                Console.WriteLine("The gate state is now opened from closed state");
            }
            else if (CurrentState == Locked)
            {
                Console.WriteLine("Please unlock the gate and open it....");
            }
            else if (CurrentState == Unlocked)
            {
                CurrentState = Opened;
                Console.WriteLine("The gate is now unlocked and opened ");
            }
        }

মেথড ২: CloseGate()

        public void CloseGate()
        {
            if (CurrentState == Opened)
            {
                CurrentState = Closed;
                Console.WriteLine("The gate has been closed successfully........");

            }
            else if (CurrentState == Closed)
            {
                Console.WriteLine("The gate is already closed.You can not close it again!!");
            }
            else if (CurrentState == Locked)
            {
                Console.WriteLine("The gate is locked. So you can not close this gate!!");
            }
            else if (CurrentState == Unlocked)
            {
                Console.WriteLine("The gate is unlocked, so it is already closed!!!!!!!");
            }
        }

মেথড ৩: LockGate()

        public void LockGate()
        {
            if (CurrentState == Opened)
            {
                Console.WriteLine("Please Close the Gate first and then lock it..");
            }
            else if (CurrentState == Closed)
            {
                CurrentState = Locked;
                Console.WriteLine("The Gate has been locked successfully..");
            }
            else if (CurrentState == Locked)
            {
                Console.WriteLine("The gate is already locked, can not lock again");
            }
            else if (CurrentState == Unlocked)
            {
                CurrentState = Locked;
                Console.WriteLine("The gate went to  Locked state from Unlocked state...");
            }
         }

এবং সবশেষে মেথড ৪: UnlockGate()

        public void UnLockGate()
        {
            if (CurrentState == Opened)
            {
                Console.WriteLine("The gate is open, can not be unlocked.....");
            }
            else if (CurrentState == Closed)
            {
                Console.WriteLine("The gate is close, can not be unlocked....");
            }
            else if (CurrentState == Locked)
            {
                CurrentState = Closed;
                Console.WriteLine("The gate is unlocked, but it is closed...");
            }
            else if (CurrentState == Unlocked)
            {
                Console.WriteLine("The gate is unlocked already...Can not unlock again");
            }
        }

তাহলে ফলাফল গিয়ে দাঁড়াল আমাদের Gate Class টির চেহারা ঠিক এরকমঃ

public class Gate
    {
        private const int Opened = 1;
        private const int Closed = 2;
        private const int Locked = 3;
        private const int Unlocked = 4;
        public int CurrentState = Opened;

        public void OpenGate()
        {
            if (CurrentState == Opened)
            {
                Console.WriteLine("The gate is already open....");
            }
            else if (CurrentState == Closed)
            {
                CurrentState = Opened;
                Console.WriteLine("The gate state is now opened from closed state");
            }
            else if (CurrentState == Locked)
            {
                Console.WriteLine("Please unlock the gate and open it....");
            }
            else if (CurrentState == Unlocked)
            {
                CurrentState = Opened;
                Console.WriteLine("The gate is now unlocked and opened ");
            }
        }

        public void CloseGate()
        {
            if (CurrentState == Opened)
            {
                CurrentState = Closed;
                Console.WriteLine("The gate has been closed successfully........");

            }
            else if (CurrentState == Closed)
            {
                Console.WriteLine("The gate is already closed. You cannot close it again!!");
            }
            else if (CurrentState == Locked)
            {
                Console.WriteLine("The gate is locked. So you cannot close this gate!!");
            }
            else if (CurrentState == Unlocked)
            {
                Console.WriteLine("The gate is unlocked, so it is already closed!!!!!!!");
            }
        }

        public void LockGate()
        {
            if (CurrentState == Opened)
            {
                Console.WriteLine("Please Close the Gate first and then lock it..");
            }
            else if (CurrentState == Closed)
            {
                CurrentState = Locked;
                Console.WriteLine("The Gate has been locked successfully..");
            }
            else if (CurrentState == Locked)
            {
                Console.WriteLine("The gate is already locked, cannot lock again");
            }
            else if (CurrentState == Unlocked)
            {
                CurrentState = Locked;
                Console.WriteLine("The gate went to  Locked state from Unlocked state...");
            }
        }

        public void UnLockGate()
        {
            if (CurrentState == Opened)
            {
                Console.WriteLine("The gate is open, cannot be unlocked.....");
            }
            else if (CurrentState == Closed)
            {
                Console.WriteLine("The gate is close, cannot be unlocked....");
            }
            else if (CurrentState == Locked)
            {
                CurrentState = Closed;
                Console.WriteLine("The gate is unlocked, but it is closed...");
            }
            else if (CurrentState == Unlocked)
            {
                Console.WriteLine("The gate is unlocked already...Cannot unlock again");
            }
        }
    }

তাহলে আমরা ক্লায়েন্ট কোড লিখবো এভাবেঃ

    public class Program
    {
        public static void Main(string[] args)
        {
            var gate = new Gate();
            gate.CurrentState = 2;//2 is for Closed State
            gate.LockGate();
            Console.ReadLine();
        }
    }

আমরা এতক্ষণ যে কোড করলাম তা কারেন্ট সিনারিও এর জন্য পারফেক্টলি কাজ করবে । কিন্তু চিন্তা করুণ যদি Gate এর জন্য নতুন কোনও ফাংশনালিটি যোগ করার হয়ে পরে তখন আমাদের Existing কোড এ হাত দিতে হবে । এবং নতুন স্টেটটির জন্য পুরো একটা মেথড লিখতে হবে যেটি কিনা বিশাল বড় । এই অবস্থা থেকে পরিত্রাণ পেতে আমরা কিছু কাজ করতে পারি যেমনঃ

  • আমরা একটি স্টেট ইন্টারফেস বানাতে পারি যেটিতে Gate class এর সবএকশন গুলো মেথড আকারে থাকবে
  • এরপর আমরা প্রত্যেকটি মেথডের জন্য একটি করে Class বানাতে পারি । এখানে এক একটি Class এক একটি একশন সম্পাদন করবে ।
  • সবশেষে আমরা if else………… এ রকম কন্ডিশনাল লজিকগুলোকে বিতাড়িত করতে পারি এতে করে State Class গুলো এর মধ্যে এদের একশন গুলো ইমপ্লিমেন্ট করে নিবে ।

তাহলে আমরা প্রথমে Gate এর একশন গুলোকে একটি ইন্টারফেস এ নিয়ে যাই । ধরি ইন্টারফেসটির নাম IGateState:

      public interface IGateState
      {
        void OpenGate();
        void CloseGate();
        void LockGate();
        void UnLockGate();
      }

দেখা যাচ্ছে আমাদের চারটি একশন মেথড গুলোকে আমরা ইন্টারফেস এ পেয়ে গেছি । এখন এই চারটি একশন এর জন্য আমরা চারটি Class বানাবো যাতে করে একশন/মেথড এর ইমপ্লিমেন্টেশন আলাদা আলাদা Class এ থাকে ।এই চারটি Class এর সবাই আমাদের IGateState ইন্টারফেসটিকে ইমপ্লিমেন্ট করবে । তাহলে চলুন ঝটপট Class গুলো বানিয়ে ফেলিঃ

OpenState Class:

    public class OpenState : IGateState
    {
        public Gate Gate { get; set; }
        public OpenState(Gate gate)
        {
            Gate = gate;
        }
        public void OpenGate()
        {
            Console.WriteLine("The gate is already open....");
        }

        public void CloseGate()
        {
            Gate.CurrentState = 1;
            Console.WriteLine("The gate state is now opened from closed state");
        }

        public void LockGate()
        {
            Console.WriteLine("Please unlock the gate and open it....");
        }

        public void UnLockGate()
        {
            Gate.CurrentState = 1;
            Console.WriteLine("The gate is now unlocked and opened ");
        }
    }

CloseState Class:

    public class CloseState : IGateState
    {
        public Gate Gate { get; set; }
        public CloseState(Gate gate)
        {
            Gate = gate;
        }
        public void OpenGate()
        {
            Gate.CurrentState = 2;
            Console.WriteLine("The gate has been closed successfully........");
        }

        public void CloseGate()
        {
            Console.WriteLine("The gate is already closed. You cannot close it again!!");
        }

        public void LockGate()
        {
            Console.WriteLine("The gate is locked. So you cannot close this gate!!");
        }

        public void UnLockGate()
        {
            Console.WriteLine("The gate is unlocked, so it is already closed!!!!");
        }
    }

LockState Class:

public class LockState : IGateState
    {
        public Gate Gate { get; set; }
        public LockState(Gate gate)
        {
            Gate = gate;
        }
        public void OpenGate()
        {
            Console.WriteLine("Please Close the Gate first and then lock it..");
        }

        public void CloseGate()
        {
            Gate.CurrentState = 3;
            Console.WriteLine("The Gate has been locked successfully..");
        }

        public void LockGate()
        {
            Console.WriteLine("The gate is already locked, cannot lock again");
        }

        public void UnLockGate()
        {
            Gate.CurrentState = 3;
            Console.WriteLine("The gate went to  Locked state from Unlocked state...");
        }
    }

UnLockState Class:

public class UnLockState : IGateState
    {
        public Gate Gate { get; set; }
        public UnLockState(Gate gate)
        {
            Gate = gate;
        }
        public void OpenGate()
        {
            Console.WriteLine("The gate is open, cannot be unlocked.....");
        }

        public void CloseGate()
        {
            Console.WriteLine("The gate is close, cannot be unlocked....");
        }

        public void LockGate()
        {
            Gate.CurrentState = 2;
            Console.WriteLine("The gate is unlocked, but it is closed...");
        }

        public void UnLockGate()
        {
            Console.WriteLine("The gate is unlocked already...Cannot unlock again");
        }
    }

এখন আমরা আমাদের Gate Class এ ফিরে যাই এবং এতক্ষণ যা যা করলাম তা কাজে লাগাই । আমরা এর আগে গেট এর স্টেট গুলো ভ্যারিয়েবলে রেখে দিয়েছিলাম । এখন ভ্যারিয়েবলের পরিবর্তে আমরা আমাদের নতুন বানানো Class গুলো ব্যবহার করবো । তাহলে নতুন Gate Class টি এরকম দাঁড়াবেঃ

    public class Gate
    {
        public IGateState OpenedState;
        public IGateState ClosedState;
        public IGateState LockedState;
        public IGateState UnlockedState;
        public IGateState CurrentGateState { get; set; }

        public Gate()
        {
            OpenedState = new OpenState(this);
            ClosedState = new CloseState(this);
            LockedState = new LockState(this);
            UnlockedState = new UnLockState(this);
            CurrentGateState = OpenedState;
        }
        public void OpenGate()
        {
            CurrentGateState.OpenGate();
        }

        public void CloseGate()
        {
            CurrentGateState.CloseGate();
        }

        public void LockGate()
        {
            CurrentGateState.LockGate();
        }

        public void UnLockGate()
        {
            CurrentGateState.UnLockGate();
        }
    }

এবং আমাদের এর আগের State Class গুলো সামান্য চেঞ্জ হয়ে এরকম হবেঃ

OpenState Class:

    public class OpenState : IGateState
    {
        public Gate Gate { get; set; }
        public OpenState(Gate gate)
        {
            Gate = gate;
        }
        public void OpenGate()
        {
            Console.WriteLine("The gate is already open....");
        }

        public void CloseGate()
        {
            Gate.CurrentGateState = Gate.OpenedState;
            Console.WriteLine("The gate state is now opened from closed state");
        }

        public void LockGate()
        {
            Console.WriteLine("Please unlock the gate and open it....");
        }

        public void UnLockGate()
        {
            Gate.CurrentGateState = Gate.OpenedState;
            Console.WriteLine("The gate is now unlocked and opened ");
        }
    }

CloseState Class:

    public class CloseState : IGateState
    {
        public Gate Gate { get; set; }
        public CloseState(Gate gate)
        {
            Gate = gate;
        }
        public void OpenGate()
        {
            Gate.CurrentGateState = Gate.ClosedState;
            Console.WriteLine("The gate has been closed successfully........");
        }

        public void CloseGate()
        {
            Console.WriteLine("The gate is already closed. You cannot close it again!!");
        }

        public void LockGate()
        {
            Console.WriteLine("The gate is locked. So you cannot close this gate!!");
        }

        public void UnLockGate()
        {
            Console.WriteLine("The gate is unlocked, so it is already closed!!!!");
        }
    }

UnLockState Class:

public class UnLockState : IGateState
    {
        public Gate Gate { get; set; }
        public UnLockState(Gate gate)
        {
            Gate = gate;
        }
        public void OpenGate()
        {
            Console.WriteLine("The gate is open, cannot be unlocked.....");
        }

        public void CloseGate()
        {
            Console.WriteLine("The gate is close, cannot be unlocked....");
        }

        public void LockGate()
        {
            Gate.CurrentGateState = Gate.LockedState;
            Console.WriteLine("The gate is unlocked, but it is closed...");
        }

        public void UnLockGate()
        {
            Console.WriteLine("The gate is unlocked already...Cannot unlock again");
        }
    }

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

   public class Program
    {
        public static void Main(string[] args)
        {
            var gate = new Gate();

            gate.CurrentGateState = gate.OpenedState;
            gate.OpenGate();
            gate.CloseGate();
            gate.LockGate();
            gate.UnLockGate();
            Console.ReadLine();
        }
    }

তো এই ছিলো আমাদের স্টেট ডিজাইন প্যাটার্ন ।

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


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