গত পর্বে আমরা ফ্যাক্টরি অবজেক্ট সম্পর্কে জেনেছি। কেন এবং কীভাবে ফ্যাক্টরি অবজেক্ট ব্যবহার করতে হয় তা নিয়ে আলোচনা করেছি। আজকে আমরা আলোচনা করব ফ্যাক্টরি মেথড প্যাটার্ন নিয়ে। আপনি যদি আগের পর্বটি পড়ে না থাকেন তাহলে এখানে ক্লিক করে পড়ে নিতে পারেন। এতে করে আজকের প্রসঙ্গটি বুঝতে আপনার বেশ সুবিধা হবে।
যাই হোক, ফ্যাক্টরি মেথড প্যাটার্ন হচ্ছে একটি ক্রিয়েশনাল ডিজাইন প্যাটার্ন। অর্থাৎ আমরা মূলত কোন ক্লাসের ইন্সট্যান্স তৈরি করতে ফ্যাক্টরি মেথড প্যাটার্ন ব্যবহার করব।
- আচ্ছা! যে কোন ক্লাসের ইন্সট্যান্স তৈরি করতে চাইলেই কি আমাকে ফ্যাক্টরি মেথড প্যাটার্ন ইউজ করতে হবে?
- না। আপনার যদি জানা থাকে যে কোন ক্লাসের ইন্সট্যান্স তৈরি করতে হবে সেক্ষেত্রে আপনি ডিপেন্ডেন্সি ইনজেকশন ব্যবহার করে কাজ সেরে ফেলতে পারেন।
- তাহলে কখন ইউজ করতে হবে?
- কম্পাইল টাইমে আপনার যদি জানা না থাকে যে কোন ক্লাসের ইন্সট্যান্স তৈরি করতে হবে তবে আপনি ফ্যাক্টরি মেথড প্যাটার্ন ব্যবহারের কথা ভাবতে পারেন।
- একটি উদাহরণ দিয়ে বুঝিয়ে বললে ভালো হত!
ধরুন, ঢাকায় আমাদের একটি গ্রোসারি স্টোর আছে। এখানে আমরা বিভিন্ন ধরণের শাকসবজি বিক্রি করি। তবে এখানে আলুর বেশ চাহিদা এবং কাস্টমাররা বিভিন্ন ধরণের আলু ক্রয় করে থাকে। যেমনঃ সাধারণ আলু, গোল আলু, মিষ্টি আলু প্রভৃতি। ধরা যাক, প্রত্যেক প্রকার আলুর জন্য আমরা ভিন্ন ভিন্ন বারকোড ব্যবহার করি। এখন কাস্টমার তার পছন্দের আলু এনে কাউন্টারে জমা দিলে, আমরা বারকোড স্ক্যানার দিয়ে রিড করে দেখি যে এটা কোন ধরণের আলু এবং সে অনুযায়ী তার থেকে দাম নেই। এখানে যেহেতু আমাদের আগেই জানা থাকছে না যে আমাদের কোন প্রকার আলু লাগবে তাই এক্ষেত্রে আমরা ফ্যাক্টরি মেথড প্যাটার্ন ব্যবহার করতে পারি।
তবে সবসময়ই যে ফ্যাক্টরি মেথড প্যাটার্ন ব্যবহার করতে হবে এমন কিন্তু নয়। ডিজাইন প্যাটার্ন আমাদের কিছু সুবিধা দেয় ঠিক তবে তার সাথে সাথে কিন্তু কোড কমপ্লেক্সটিও বাড়িয়ে দেয়। সেই ক্ষেত্রে হিতে বিপরীত যেন না হয় সেদিকে খেয়াল রাখতে হবে। এই কথাটা একটি সফটওয়্যার ডিজাইন প্রিন্সিপল এভাবে বলছেঃ
Keep it simple, stupid!
মজার তাই না? এই প্রিন্সিপলকে সংক্ষেপে বলা হয় KISS. যাইহোক, সমস্যার উপর ভিত্তি করে আমাদের সমাধান তৈরি করা উচিৎ। প্রথমে সহজ সমাধান দিয়ে শুরু করা উচিৎ এরপর যদি দেখা যায় এভাবে আর কোড মেইনটেইন করা যাচ্ছে না সেক্ষেত্রে আমরা কোড রিফ্যাক্টর করতে পারি।
তো আমাদের বিজনেস প্রবলেমটি যেহেতু খুব সোজা সেহেতু আমরা সহজ একটি সমাধান লিখি। এক্ষেত্রে সমাধানটি হচ্ছে, ফ্যাক্টরি অবজেক্ট ব্যবহার করা। পরে আমরা বিজনেস আরও কমপ্লেক্স করব এবং এই কোড রিফ্যাক্টর করে ফ্যাটরি মেথড প্যাটার্ন দিয়ে ইমপ্লিমেন্ট করব। এখন, ফ্যাক্টরি অবজেক্ট ব্যবহার করে সমাধান লিখার পর আমাদের কোড বেজের যে অবস্থা হলঃ
(গিস্টে ক্লাসগুলো বর্ণানুক্রমে সর্ট হয়ে যাচ্ছিল তাই ক্লাসের নামের আগে সিরিয়াল নাম্বার বসিয়ে দিয়েছি।)
আগের পর্বটি যদি পড়ে থাকেন তাহলে এই কোড বুঝতে খুব একটা সমস্যা হবার কথা নয়। এখানে, আমরা আলু তৈরির জন্য একটি ফ্যাক্টরি অবজেক্ট বানিয়েছি। ফ্যাক্টরি অবজেক্ট ইনিশিয়ালাইজ করার সময় আমরা type প্যারামিটারের জন্য একটি আর্গুমেন্ট পাঠাচ্ছি। এবং সে এই আর্গুমেন্ট অনুযায়ী আলুর অবজেক্ট তৈরি করে রাখছে। পরবর্তীতে আমরা গেট মেথড কল করলে আমাদেরকে অবজেক্টটি ফেরত দিচ্ছে।
এবার তাহলে আমরা বিজনেস ডোমেইন টা একটু চেঞ্জ করি। ধরা যাক, আমাদের গ্রোসারী স্টোর বেশ ভালো চলতে লাগলো। তো আমরা সিদ্ধান্ত নিলাম যে ঢাকার বাইরেও আমরা শাখা খুলব। আমরা চট্টগ্রাম দিয়ে শুরু করলাম। তো এখন প্রবলেম হচ্ছে যে, ঢাকা শাখার জন্য আমরা যে সরবরাহকারীর কাছে থেকে আলু নিতাম চট্টগ্রাম শাখার জন্য তো তার কাছে থেকে আলু নিতে পারব না। চট্টগ্রামের কোন সরবরাহকারীর কাছে থেকে যদি নেয়া যায় তাহলে দাম নিশ্চয়ই অনেক কম পরবে, তাই না?
তো, আমাদের যেহেতু আলাদা আলাদা সরবরাহকারীর থেকে আলু সংগ্রহ করতে হবে সেহেতু আমাদের ফ্যাক্টরিও লাগবে আলাদা আলাদা। পূর্বে পটেটো ফ্যাক্টরির কন্সট্রাকটর ব্যবহার করে আমরা আমাদের প্রয়োজন মত আলুর অবজেক্ট তৈরি করে নিতাম। তবে এখন আমরা যেটা করব সেটা হচ্ছে কনস্ট্রাকটরের বদলে মেথড ব্যবহার করব। আর এই মেথড ডিক্লেয়ার করা থাকবে একটি এবস্ট্রাক্ট ফ্যাক্টরি ক্লাসে এবং আমাদের যতগুলো ফ্যাক্টরি থাকবে সবাই এই ক্লাসকে ইনহেরিট করবে এবং মেথডটিকে নিজের মত ইমপ্লিমেন্ট (ওভার-রাইড) করবে। নিচের ক্লাস ডায়াগ্রাম টা দেখলে আরও পরিষ্কার বুঝতে পারবেন।
তো ফ্যাক্টরি মেথড প্যাটার্নে দুই ধরণের অবজেক্ট থাকে। যথাঃ ক্রিয়েটর এবং প্রডাক্ট। ক্রিয়েটর ফ্যাক্টরি হিসেবে কাজ করে। অর্থাৎ ক্রিয়েটর কোন একটি অবজেক্ট তৈরি করে এবং এজন্যই একে ফ্যাক্টরি বলা হয়। আর ক্রিয়েটর যে অবজেক্টটি তৈরি করে রিটার্ন করে তাকে প্রডাক্ট বলে। যেহেতু মেথড ব্যবহার করে আমরা অবজেক্ট তৈরি করি তাই একে ফ্যাক্টরি মেথড প্যাটার্ন বলা হয়। তো, আমাদের ক্ষেত্রে ক্রিয়েটর/ফ্যাক্টরি হবে DhakaiyaPotatoFactory এবং ChittagonianPotatoFactory আর প্রডাক্ট হবে DhakaiyaRegularPotato, DhakaiyaRoundPotato, DhakaiyaSweetPotato, ChittagonianRegularPotato, ChittagonianRoundPotato, ChittagonianSweetPotato.
ঝটপট কোড লিখে ফেলি তাহলে আমরা?
বেশি কোড দেখে ঘাবড়ে যাবার কিছুই নেই। কোড খুব সহজ এখানে! আমারা শুধু শাখা অনুযায়ী দায়িত্বটা ভাগ করে দিয়েছি আর কি। আগে আমাদের ফ্যাক্টরি অবজেক্ট ছিল একটি, শুধু মাত্র পটেটো ফ্যাক্টরি। তখন আমরা কন্সট্রাক্টর দিয়ে আমাদের পছন্দের অবজেক্ট ইনিশিয়ালাইজ করতাম। আর এখন আমাদের প্রত্যেক শাখা অনুযায়ী আলাদা ফ্যাক্টরি আছে, এই আরকি! এবার যদি আমরা সিলেটে গিয়ে একটি শাখা খুলি, কী করতে হবে বলুন তো?
নতুন একটি ফ্যাক্টরি বানাতে হবে যেটা কিনা পটেটো ফ্যাক্টরিকে ইনহেরিট করবে। এবং আলুর ধরণ অনুযায়ী আরও তিনটা ক্লাস বানাতে হবে যেটা কিনা পটেটো ক্লাস কে ইনহেরিট করবে। ব্যস, এতোটুকুই! তবে খেয়াল রাখতে হবে যে অবজেক্টের ভেরিয়েশন অনুযায়ী ক্লাসের সংখ্যা কিন্তু বেড়েই চলবে। তাহলে, কী বুঝলাম?
Design pattern gives us flexibility but it comes with a cost.
যাইহোক, এবার যদি কেউ জিজ্ঞাসা করে ফ্যাক্টরি মেথড প্যাটার্ন কী, বলা যাবে?
ফ্যাক্টরি মেথড প্যাটার্ন হচ্ছে একটি ক্রিয়েশনাল ডিজাইন প্যাটার্ন যেটা কিনা অবজেক্ট তৈরি করার ইন্টারফেস প্রদান করে সুপারক্লাসে/বেজ ক্লাসে কিন্তু ইমপ্লিমেটেশনের দায়িত্ব দেয় সাবক্লাস/ চাইল্ড ক্লাস কে।
এক্ষেত্রে বেজ ক্লাসে যদি ডিফল্ট কোন ইমপ্লিমেন্টেশন দেয়া থাকে তাহলে আমরা বলতে পারি যে, চাইল্ড ক্লাস কে সেই ইমপ্লিমেন্টেশন ওভার-রাইড করার সুযোগ দেয়।
আর একটি ব্যাপার হচ্ছে, ইন্টারফেস মানে কিন্তু শুধুই "ইন্টারফেস টাইপ" না। একটি মেথড যদি অন্য কোন অবজেক্টের জন্য উন্মুক্ত করে দেওয়া হয় যাতে করে সে মেথডটি একসেস বা ম্যানুপুলেট করতে পারে তাহলে মেথডের এই যে উন্মুক্ত অবস্থা একেও ইন্টারফেস বলে এক্সপ্লেইন করা হয়। এক্ষেত্রে ইন্টারফেস বলতে প্রবেশদ্বারের মত কিছু একটা বোঝানো হয়। আমরা যেমন বলি না, ইউজার ইন্টারফেস? ঠিক ওইরকম অর্থে। যার সাহায্যে কোন কিছু একসেস করা যায় তাই ইন্টারফেস।
তো, আজকের মত এখানেই শেষ করছি। আগামী পর্বে আমরা গল্প করব এবস্ট্র্যাক্ট ফ্যাক্টরি প্যাটার্ন নিয়ে।