নাল অবজেক্ট প্যাটার্ন (Null Object Pattern)


ইনি সাহেব আমাদের বলেন যে : Just because I don’t have anything and don’t do anything, it does not mean that I am not smart.  By not having anything, I don’t take up much resource and can be shared among many.  By not doing anything, I am doing the right thing. বেশ ভাব নিয়ে চলেন এই প্যাটার্ন । চলুন দেখি ভাব নেয়ার কি কি আছে ইনি সাহেবের 😛

কি : কোনও কাঙ্ক্ষিত অবজেক্ট না পাওয়া গেলে অর্থাৎ নাল হলে তার রিপ্লেসমেন্ট হিসেবে নাল অবজেক্ট ব্যবহৃত হয় । যেমন আমার খোজে আমার বাসায় একজন আসে এবং আমি যদি নাল হয়ে থাকি, মানে বাসায় না থাকি এবং যদি আমার ছোট ভাই বলে এখন ভাইয়া বাসায় নাই , সন্ধ্যার পর আসবে এক্ষেত্রে আমার ছোট ভাই হচ্ছে নাল অবজেক্ট যে কিনা আমার নাল হওয়াটাকে মানে আমার বাসায় না থাকাটাকে বর্ণনা করছে ।

উদাহরণঃ  যেমন কেউ যদি এপ্লিকেশন থেকে যদু নামে একজন ভদ্রলোকের ইনফরমেশন দেখতে চায় এবং যদু নামক ভদ্রলোক যদি এপ্লিকেশনের ইউজার না হয়ে থাকেন তাহলে কিন্তু Null Reference Exception দেখাবে  অথবা আমাদের বার বার চেক করতে হবে , মানে Redundant Code লিখতে হবে । যেটি একটি ব্যাড প্র্যাকটিস ।

কেনো  ইউজ করবো : 

  1.  নাল রেফারেন্স ইক্সেপ্সহন এর করাল থাবা থেকে এপ্পলিকেশন ইউজারদের রক্ষা করা অর্থাৎ এমন কোনও ইরর মেসেজ ইউজার কে না দেখানো , যেটা সে বুঝতে না পারে (উদাঃ 404 ইরর )
  2. এক্সেপশন হ্যান্ডেলিং এর জন্য বার বার চেক করা মানে রিডান্ডেন্ট কোড  না লিখা  ।
  3. একটা অবজেক্ট নাল হলে এর আচরণ কেমন হবে তা ঠিক করে দেয়া  ।

চলুন দেখে আসি কিভাবে ইমপ্লিমেন্ট করা যায় :

প্রথমে আমরা একটি সিম্পল User ক্লাস বানাই

   public class User
    {
        public String Name { get; set; }
        public String Roll { get; set; }
    }

এখন আমরা একটি Interface বানাবো যার কাজ হচ্ছে শুধু মাত্র ইউজারের Role রিটার্ন করা :

    public interface IUser
    {
        String GetUserRole();
    }

User ক্লাস IUser ইন্টারফেস টে ইমপ্লিমেন্ট করলে ব্যাপার টা এরকম দাঁড়াবে :

public class User:IUser
    {
        public String Name { get; set; }
        public String Roll { get; set; }
        public string GetUserRole()
        {
            return Role;
        }
    }

এখন আমরা একটা User এর লিস্ট বানাবো , সেই লিস্টে কিছু User এর অবজেক্ট ঢুকাবো এবং সেই মেথডটি User এর লিস্ট টা রিটার্ন করবে ।  মেথড টার নাম দেই PopulateUserList ।
এ কাজটি UserRepository নামে ক্লাসে করা হয়েছে ।

public class UserRepository
    {
        private static List PopulateUserList()
        {
            List userList = new List();
            userList.Add(new User()
            {
                Name = "Zodu",
                Roll = "bit0215"
            });

            return userList;
        }
    }

এখন আমাদের আরেকটি মেথডের দরকার হবে যেটি প্যারামিটার হিসেবে User এর নাম নিবে এবং userList থেকে খুজে ঐ ইউজার রিটার্ন করবে . মেথডটির নাম দেই GetUserRoleByName

এর ইমপ্লিমেন্টেশন হবে এই রকম :

public static User GetUserRoleByName(string name)
        {
            List userList = PopulateUserList();

            User user = (from p in userList
                         where p.Name == name
                         select p).FirstOrDefault();
            return user;
        }

সো টোটাল ক্লাশটা দেখতে ঠিক এ রকম :

public class UserRepository
    {
        public static User GetUserRoleByName(string name)
        {
            List userList = PopulateUserList();

            User user = (from p in userList
                         where p.Name == name
                         select p).FirstOrDefault();
            return user;
        }

        private static List PopulateUserList()
        {
            List<User> userList = new List<User>();
            userList.Add(new User()
            {
                Name = "zodu",
                Roll = "bit0215"
            });

            return userList;
        }
    }

এখন মেইন ফাংশন থেকে User এর রোল প্রিন্ট করবো এই ভাবে:

class Program
    {
        static void Main(string[] args)
        {
            IUser user = UserRepository.GetUserRoleByName("zodu");
            String role = user.GetUserRole();
            Console.WriteLine("User role is: {0}",role);
        }
    }

আউটপুট: User role is:BIT0215
এখানে লক্ষণীয় ব্যপার হচ্ছে আমরা UserList এ শুধু আমরা একজন ইউজার ঢুকিয়েছিলাম , আমরা যদি ঐ User ছাড়া অন্য কোনও ইউজার এর রোল পেতে চাই তাহলে সেটা রীতিমত আঁতকে ওঠার মত ব্যপার হবে । এই দেখুন প্রমাণ ঃ

“zodu” চেঞ্জ করে  “Modu” দিলে  Null Reference Exception দেখবেন ।

পরিত্রাণের উপায়ঃ

  1. প্রথম উপায় হচ্ছে  চেক করা User Null কিনা । Null হলে ভিন্ন মেসেজ দেয়া ইউজার কে ।যেমন :
    class Program
        {
            static void Main(string[] args)
            {
                IUser user = UserRepository.GetUserRoleByName("Modu");
                if (user != null)
                {
                    String role = user.GetUserRole();
                    Console.WriteLine("User role is: {0}", role);
                }
                else
                {
                    Console.WriteLine("Modu is not found in the database!!!!!!!!!!");
                }
    
            }
        }

    এই এখন এটা রান করলে আমাদের বেশ ভদ্রসদ্র একটা মেসেজ দিবে

    Modu is not found in the database!!!!!!!!!!

    কিন্তু অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং এ if else জিনিসটা খুবই বাজে হিসেবে গন্য করা হয় । ধরা যাক আমাদের এপ্লিকেশনে ১০০০ যায়গায় User এর অবজেক্ট নিয়ে কাজ  করা হয় । এখন এই ডিজাইনে আমাদের এক হাজার জায়গায় লিখতে হবেif (user != null) যা খুবই বাজে প্র্যাকটিস ।

  2. দুই নম্বর পরিত্রাণের উপায় এবং সবচেয়ে ভালো প্র্যাকটিস  হচ্ছে একটি NullUser ক্লাশ বানানো । এবং ডিজাইন একটু চেঞ্জ করা ।তাহলে দেখি কিভাবে আরোও বেটার ডিজাইনের দিকে আমরা যেতে পারি । এক্ষেত্রে আসলে আমাদের UserRepositoryক্লাশটা Refactor করতে হবে এবং NullUser নামে আর একটা ক্লাশ বানাতে হবে ।আমাদের NullUser টা দেখতে এই রকম হবে :
    public class NullUser : IUser
        {
            public string GetUserRole()
            {
                return "Sorry We could not find this user";
            }
        }

দেখতে পাচ্ছি আমাদের NullUser এবং User ক্লাশ উভয়েই IUser ইন্টারফেসকে ইমপ্লিমেন্ট করে । তাই আমরা GetUserByName

মেথড থেকে User রিটার্ন করা বাদ দিয়ে শুধুমাত্র Iuser রিটার্ন করতে পারি ।

এবং লিস্ট থেকে User খুজে নিয়ে আমরা রিটার্ন করার সময় চেক করে নিতে পারি User Null কিনা ।
নাল হলে আমরা NullUser এর অবজেক্ট রিটার্ন করে দিতে পারি , আর না হলে শুধুমাত্র Userরিটার্ন করে দিতে পারি ।

সো Refactoring এর পর আমাদের UserRepository  ক্লাশটা দেখতে ঠিক এরকম টা হবে

 

public class UserRepository
    {
        public static IUser GetUserByName(string name)
        {
            List<User> userList = PopulateUserList();

            User user = (from p in userList
                         where p.Name == name
                         select p).FirstOrDefault();
            if (user == null)
            {
                return new NullUser();
            }
            return user;
        }

        private static List<User> PopulateUserList()
        {
            List<User> userList = new List<User>();

            userList.Add(new User()
            {
                Name = "forhad",
                Roll = "bit0213"
            });

            return userList;
        }
    }

এখন ক্লায়েন্ট কোড হচ্ছে আমাদের এরকম:

class Program
    {
        static void Main(string[] args)
        {
            IUser user = UserRepository.GetUserRoleByName("Modu");

            String role = user.GetUserRole();
            Console.WriteLine(role);
        }
    }

আমরা জানি যে আমাদের Repository তে “Modu” নামক User নেই সো এখন আর ইরর মেসেজ দেখাবে না এবং আমাদের এপ্লিকেশনে ১০০০ বার User Null কিনা এটা আর চেক করার দরকার ই নেই । NullUser দিয়েই আমরা ১০০০ যায়গার চেকিং করার কষ্ট কমিয়ে দিয়েছি ।
রান করলে কনসোলে দেখা যাবে যে Sorry we could not find this user”

“Modu” চেঞ্জ করে “zodu” দিলে “zodu” এর Roll দেখাবে “BIT0215

আমরা শিখে ফেললাম নাল অবজেক্ট ডিজাইন প্যাটার্ন । ডিজাইন প্যাটার্ন আসলেই অনেক মজার ।
শুরুতেই ইনি সাহেব ঘোষণা দিয়ে ছিলেন না ইনি স্মার্ট? , অতএব প্রমাণিত হল ইনি আন্তর্জাতিক মানের মান সম্মত স্মার্ট 😛
–(প্রমাণিত)

Advertisements

One thought on “নাল অবজেক্ট প্যাটার্ন (Null Object Pattern)

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