Sunday, October 29, 2017

C# For Beginners, Part-33 ( Delegate )

আজকে আমরা  Delegate নিয়ে কথা বলবো । শুনে ভয় পাবার কিছু নেই , প্রথম প্রথম অন্যরকম লাগলেও , ব্যবহার করতে করতে ঠিক হয়ে যাবে ।। চলো একটা ছোট উদাহরণ দেখে আসি ----

using System;

public delegate void HelloFunction(string message);
    class Program
    {
        public static void Main(string[] args)
        {
            HelloFunction r = new HelloFunction(hello);
            r("Hello Delegate");
        }
        public static void hello(string s)
        {
            Console.WriteLine(s);
            Console.ReadKey();
        }
    }

আমরা একটা Delegate ক্রিয়েট করেছি ।। delegate  কিওয়ারড ইউজ করে । Delegate  অনেকটাই মেথোডের মতোই । অ্যাকসসেস মোডিফায়ার আছে , রিটার্ন টাইপ আছে ।। প্যারামিটার আছে । হুবহু , একটা মেথোডের মতোই , বাট একটা জিনিস একটু অমিল সেটা হলো - এটা মূলত অন্য একটা মেথোডকে পয়েন্ট করে । ঠিক যেমনটা , আমরা একটা ক্লাসের অব্জেক্ট ক্রিয়েট করার সময় যেমন ,
রেফারেন্স ভ্যারিয়েবল ডিক্লেয়ার করি , যেটা ওই ক্লাসের অব্জেক্টকে পয়েন্ট করে , ঠিক প্রায় একইরকম ভাবে এখানে Delegate জিনিসটা ব্যবহার করা হয় , অন্য একটা মেথোড\ফাংশন কে পয়েন্ট করবার জন্য ।। একটা জিনিস মনে রাখা জরুরী যে - আমাদের  Delegate যে মেথোডকে পয়েন্ট করবে , সেই মেথোড এর  Signature এবং আমাদের  Delegate এর  Signature সেইম হতে হবে ।।

আমি  HelloFunction নামে একটা  Delegate ক্রিয়েট করলাম ।। তারপর , HelloFunction r = new HelloFunction(hello) এর মাধ্যমে আমি এই  Delegate এর অব্জেক্ট ক্রিয়েট এর সময়ই এর কন্সট্রাক্টরে hello নামক মেথোডের নাম দিয়েছি ।। মানে , আমাদের এই  Delegate , hello নামক মেথোডকে পয়েন্ট করবে ।। তারপর , "Hello Delegate" নামক স্ট্রিং প্যারামিটার হিসেবে পাঠিয়ে সেটাকে কনসল স্ক্রিনে শো করালাম , hello নামক মেথোড দিয়ে , বাট নেপথ্যে কাজ করে গেলো  , HelloFunction নামক delegate ।। এই জন্য  Delegate কে বলা হয় , Function Pointer |

আচ্ছা আমরা কিন্তু , ওপরের কোড-এ ডেলিগেট ক্রিয়েট না করেও , খুব সহজেই নিচের মতো করে কোড লিখতে পারতাম ।।
using System;

    class Program
    {
        public static void Main(string[] args)
        {

            hello("Hello Delegate");
        }
        public static void hello(string s)
        {
            Console.WriteLine(s);
            Console.ReadKey();
        }
    }

একই আউটপুট পাবো , বাট আমরা ডেলিগেট আসলে কিভাবে ? কাজ করে ? এটা বুঝতে পারবো না ।। তাই , আমি ডেলিগেট ইউজ করেই লিখেছি ।। এই পর্যন্ত , যতো টুকু হলো - সেইটুকুই আমরা আরো ভালোভাবে দেখে নেই , তারপর আমরা বাকি আলোচনায় এগুবো । উপরের টুকু ভালো করে না বুঝে , নিচে এগুনো ঠিক হবে না ।।


এবার আমরা শিখবো - কেনো এর এতো প্রয়োজনীয়তা ????? চলো একটা কোড দেখে আসি -----------------

using System;
using System.Collections.Generic;
   public class Program
    {
        public static void Main(string[] args)
        {

            List<Employee> emplist = new List<Employee>();
            emplist.Add(new Employee() { ID = 110, name = "Joy", Salary = 40000, Experience = 5 });
            emplist.Add(new Employee() { ID = 111, name = "Jony", Salary = 40000, Experience = 5 });
            emplist.Add(new Employee() { ID = 112, name = "Joga", Salary = 30000, Experience = 2 });
            Employee.PromoteEmployee(emplist);
        }
      
    }
public class Employee
{
    public int ID { get; set; }
    public string name { get; set; }
    public int Salary { get; set; }
    public int Experience { get; set; }

    public static void PromoteEmployee(List<Employee>employeelist)
    {
        for(int i=0;i<3;i++)
        {
            if(employeelist[i].Experience>=5)
            {
                Console.WriteLine(employeelist[i].name + " Promoted");
              
            }
          
        }
        Console.ReadKey();
    }
}

আমরা , একটা  Employee ক্লাসের ভেতরে - চারটে প্রোপার্টি ক্রিয়েট করেছি ।। একটা মেথোড ক্রিয়েট করে ,প্যারামিটার হিসেবে লিস্ট ইউজ করেছি । যেহেতু , এর আগে লিস্ত নিয়ে কথা বলি নি , তাই একটু নতুন লাগতে পারে , কিন্তু ভয় পাবার কিছু নেই ।। এটা আহামরি কোনো ব্যপার নয় ।। তারপর আমরা , অপর ক্লাসের মেইন মেথোডে গিয়ে -আরো একটা লিস্ট ক্রিয়েট করেছি । যেখানে , প্রোপারটির মান গুলো সেট করে দিয়েছি । তারপর , সেটাকে আমাদের Employee  ক্লাসের ভেতরের মেথোডে প্যারামিটার হিসেবে পাঠিয়েছি ।। আশা করি , কিছুটা ক্লিয়ার হয়েছে ।।

এখন একটা জিনিস খেয়াল করে দেখো যে -- আমরা আমাদের এমপ্লয়িদের জন্য একটা শর্ত বেধে দিয়েছি , যদি অভিজ্ঞতা ৫ বছর / তার চেয়ে বেশী হয় , তাহলে -- তাদের প্রোমোশন হবে , অন্যথায় হবে না , তাই না ?? বাট মনে করো , আমরা শর্ত গুলো চেইঞ্জ করতে চাই ।।তখন কি করতে হবে ??? আমাদের এই এমপ্লয়ি ক্লাসের ভেতরে এসে , সব শর্ত ইত্যাদি চেইঞ্জ করতে হবে । যে কারণে  , এই প্রোগ্রামের ফ্লেক্সিবিলিটি হারাবে ।। তাই যদি , এই ক্লাসে না ঢুকেই বাইরে থেকে আমরা এই ক্রাইটেরিয়াগুলো চেইঞ্জ করতে পারতাম !! তাহলে খুবই ভালো হতো , তাহলে যে কোনো সময় -- আমরা বাইরে থেকেই ইচ্ছে মতো সবকিছু চেইঞ্জ করতে পারতাম ।। তাই না ??? তাহলে আমরা এই একই ক্লাসকে বার বার ইউজ করতে পারবো ।। চলো বড়ো একটা কোড দেখে আসি ----

using System;
using System.Collections.Generic;
    class Program
    {
        public static void Main(string[] args)
        {

            List<Employee> emplist = new List<Employee>();
            emplist.Add(new Employee() { ID = 110, name = "Joy", Salary = 40000, Experience = 5 });
            emplist.Add(new Employee() { ID = 111, name = "Jony", Salary = 40000, Experience = 5 });
            emplist.Add(new Employee() { ID = 112, name = "Joga", Salary = 30000, Experience = 2 });
            IsPromotable isPromotable = new IsPromotable(promote);

            Employee.PromoteEmployee(emplist, isPromotable);
        }
       public static bool promote(Employee emp)
        {
           if(emp.Experience>=5)
           {
               return true;
           }
           else
           {
               return false;
           }
        }
      
    }
 delegate bool IsPromotable(Employee emp);
 class Employee
{
    public int ID { get; set; }
    public string name { get; set; }
    public int Salary { get; set; }
    public int Experience { get; set; }

    public static void PromoteEmployee(List<Employee> employeelist, IsPromotable s)
    {
        for(int i=0;i<3;i++)
        {
            if(s(employeelist[i]))
            {
                Console.WriteLine(employeelist[i].name + " Promoted");
              
            }
          
        }
        Console.ReadKey();
    }
}


ভেঙ্গে ভেঙ্গে ,একটু বোঝার ট্রাই করি , আসলে কি হয়েছে ??? প্রথমে আমরা একটা ডেলিগেট  ক্রিয়েট করলাম । [  delegate bool IsPromotable(Employee emp) ]
যার টাইপ হলো , বুলিয়ান আর প্যারামিটার টাইপ হলো এমপ্লয়ী ক্লাস ।। আচ্ছা , যেহেতু আমরা একটা ডেলিগেট ক্রিয়েট করেই ফেললাম , তাই সেইম সিগনেচার-এই আরেকটা মেথোড ক্রিয়েট করতে হবে , যাকে এই ডেলিগেট পয়েন্ট  করবে ।। 

  public static bool promote(Employee emp)
        {
           if(emp.Experience>=5)
           {
               return true;
           }
           else
           {
               return false;
           }
        }

এখানে , আমরা এর ঠিক আগেরবার ডেলিগেট ছাড়া করার সময় যখন ইফ স্টেইট্মেন্ট এর ভেতরে যে শর্ত ইউজ করেছিলাম ।  এখনো , তাই করলাম ।  ।  আচ্ছা , এইবার আমরা
IsPromotable isPromotable = new IsPromotable(promote); ডেলিগেট এর নামে ইন্সটযান্স ক্রিয়েট করার সময় - ডেলিগেট এর কন্সট্রাক্টরে - promote মেথোডের নাম দিলাম ।। এর মানে , ডেলিগেটকে যখনই ডাকা হবে , তখনই ডেলিগেট নিজে কোনো কিছু না করে এই  promote নামক মেথোডকে কল করবে ( পয়েন্ট করবে ) ।

এখন এই ডেলিগেটকে প্যারামিটার হিসেবে  Employee নামক সেকেন্ড ক্লাসের PromoteEmployee নামক মেথোডে প্যারামিটার হিসেবে ,পাঠিয়ে দিলাম । ভয় পাবার কিছু নেই , প্যারামিটার হিসেবে ডেলিগেট পাস করানো যায় । । public static void PromoteEmployee(List<Employee> employeelist, IsPromotable s) এর মাধ্যমে ,  PromoteEmployee মেথোডেও সেই ডেলিগেটকে টেইক করলো ।।  তারপর , ইফ এর ভেতরে শর্তকে - if(s(employeelist[i])) দ্বারা প্রতিস্থাপিত করলাম । ।  আচ্ছা , এবার ইফ এর ভেতরে কি কাজ হচ্ছে ???
চলো হালকা করে ব্যাখ্যা করে নেই ।।
যখন  s(employeelist[i]) লিখা হলো , তখন - আমরা আমাদের ডেলিগেটকে কল করে তার ভেতরে পযারামিটার হিসেবে লিস্ট এর প্রথম এলিমেন্ট দিয়ে দেলাম । ডেলিগেট তখন , সে যে মেথোডকে পয়েন্ট করে , সেই  promote মেথোডকে প্যারামিটার হিসেবে লিস্ট এর প্রথম এলেমেন্ট পাস করে , আর আমাদের মেথোড এই এলিমেন্ট এর  (emp.Experience>=5) Experience নামক প্রোপার্টি চেক করে True / False রিটার্ন করে ।। যেটার ভিত্তিতে ,

 if(s(employeelist[i]))
            {
                Console.WriteLine(employeelist[i].name + " Promoted");
              
            }

লাইন এক্সিকিউট হয় ।। আশা করি , কিভাবে ? ডেলিগেট ইউজ করে কাজ করলাম সেটা ক্লিয়ার হয়ে গেছে , অনেকটাই ।।

এখন আমাদের অনেকেই , এতটা কোড লিখতে আলস্য প্রকাশ করে , আমরা কিন্তু উপরের কোডকেই আরো অনেক কম কোদেই লিখতে পারবো ।। চলো দেখে আসি ,
using System;
using System.Collections.Generic;
    class Program
    {
        public static void Main(string[] args)
        {

            List<Employee> emplist = new List<Employee>();
            emplist.Add(new Employee() { ID = 110, name = "Joy", Salary = 40000, Experience = 5 });
            emplist.Add(new Employee() { ID = 111, name = "Jony", Salary = 40000, Experience = 5 });
            emplist.Add(new Employee() { ID = 112, name = "Joga", Salary = 30000, Experience = 2 });
          

            Employee.PromoteEmployee(emplist, emp1=>emp1.Experience>=5);
        }
     
      
    }
 delegate bool IsPromotable(Employee emp);
 class Employee
{
    public int ID { get; set; }
    public string name { get; set; }
    public int Salary { get; set; }
    public int Experience { get; set; }

    public static void PromoteEmployee(List<Employee> employeelist, IsPromotable s)
    {
        for(int i=0;i<3;i++)
        {
            if(s(employeelist[i]))
            {
                Console.WriteLine(employeelist[i].name + " Promoted");
              
            }
          
        }
        Console.ReadKey();
    }
}

আমাদের ডেলিগেট এর জন্য আলাদ কোনো মেথোড ক্রিয়েট করতে হলো না ।। Employee.PromoteEmployee(emplist, emp1=>emp1.Experience>=5); খুব সহজেই এক লাইনেই সব কাজ করে দিলাম , তাই না ?? কিন্তু তুমি যদি এর বেসিকটা বুঝতে চাও , কিভাবে কাজ করছে ?? তাহলে তোমায় -- সেই আগের কোডটাই প্র্যাক্টিস করা উচিত ।। তারপর তুমি যখন পুরো বিষয় ক্লিয়ার হয়ে যাবে , তখন না হয় তুমি শর্ট -কাট ইউজ করতে পারবে ।।  emp1=>emp1.Experience>=5 এই এক্সপ্রেশনকে , ল্যামডা এক্সপ্রেশন বলা হয় ।। আচ্ছা , একটা জিনিস মাথায় রেখো - এই ল্যামডা এক্সপ্রেশন দেখতে ছোট হলেও , রানটাইমে কিন্তু -- সেই একই কাজ হচ্ছে । ডিফল্টভাবেই , ডেলিগেট এর অব্জেক্ট ক্রিয়েট হচ্ছে, তারপর ফাংশনে প্যারামিটার পাস হচ্ছে ,সেইম কাজই হচ্ছে  ...ইত্যাদি ।। তো আশা করি , বুঝতে পারলে ডেলিগেট ইউজ করে আমরা আমাদের প্রোগ্রামকে অনেকটাই ফ্লেক্সিবল করতে পারি ।।

No comments:

Post a Comment