আপনি কী OOP (অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিং)-এর পুরো শক্তি ব্যবহার করছেন নাকি বঞ্চিত হচ্ছেন?
যদি আপনি একটি অবজেক্টের টাইপের ভিত্তিতে সিদ্ধান্ত নেন তবে আপনি OOP-এর একটি গুরুত্বপূর্ণ বৈশিষ্ট্য থেকে বঞ্চিত হচ্ছেন: পলিমরফিজম।
টাইপ সিদ্ধান্ত সাধারণত কেস স্টেটমেন্টের ভিতরে নেওয়া হয় (যে OO বান্ধব নয়) এবং এই নিবন্ধে আপনি শিখবেন সেগুলো সরিয়ে কীভাবে ভালো কোড লিখতে হয়।
টাইপ চেক করা
আমি একটি উদাহরণ দিয়ে শুরু করি যেখানে আমরা পলিমরফিজমের সুবিধা নিচ্ছি না।
আমরা "রক, পেপার, সিসরস" গেম ইমপ্লিমেন্ট করতে চাই এবং আমরা একটি Game ক্লাস এবং প্রতিটি moguable মuves এর জন্য একটি ক্লাস রাখতে সিদ্ধান্ত নিয়েছি।
বিজেতা চেক করার জন্য আমরা Game-এ একটি play মেথড ইমপ্লিমেন্ট করব:
class Game def self.play(move1, move2) return :tie if move1 == move2 move1.wins_against?(move2) end end
এখানে moguable মুভসের একটি (অন্যান্য একই প্যাটার্ন অনুসরণ করে):
class Rock def wins_against?(other_move) case other_move when Paper then false when Scissors then true end end end
এখন আমরা play মেথডকে দুটি মুভসহ কল করতে পারি এবং জানতে পারব প্রথম মুভটি জিতেছে কিনা।
p Game.play(Rock.new, Paper.new) # false
ঠিক আছে, এটি কাজ করছে, কিন্তু কি আমরা আরও ভালো করতে পারি? কি সে বদশরৎ কেস স্টেটমেন্টটি সরাতে পারি?
টাইপ চেকিং এর পরিবর্তে পলিমরফিজম
হ্যাঁ! আমরা OOP ফান্ডামেন্টাল ব্যবহার করে টাইপ-চেকিং কেস স্টেটমেন্টটি সরাতে পারি।
আইডিয়া হলো আমরা করেন্ট ক্লাস জানি সেটি ব্যবহার করে অন্য মুভ অবজেক্টকে পুচ্ছি সেটি আমাদের বজিয়ে দিতে পারে কিনা।
এবং আমরা একটি মেথড নাম ব্যবহার করব যা আমাদের ক্লাসের জন্য স্পেসিফিক ( Rock-এর জন্য মেথডের নাম হতে পারে: do_you_beat_rock?)।
রুবিতে, পলিমরফিজম হলো যেকোনো মেথড কল (OOP পরিভাষায় মেসেজও বলা হয়) যেকোনো অবজেক্টে পাঠাতে পারা অবজেক্টের ক্লাস চেক না করেই। এটিকে "ডাক টাইপিং"-ও বলা হয়, কিন্তু আমি সেই টার্ম পছন্দ করি না 🙂
জাভাতে (একটু ধৈর্য ধারন করুন…), আপনার "ইন্টারফেস" নামে একটি জিনিস থাকে যা আপনাকে একটি সেট মেথড একটি ক্লাসে কম্পাইলার লেভেলে ইমপ্লিমেন্ট করতে বাধ্য করে।
রুবিতে সেটি নেই (হয়তো ভালোই), তাই আপনাকে টেস্টিং-র ওপর নির্ভর করতে হবে।
চলুন এই নতুন ইমপ্লিমেন্টেশন কীভাবে দেখায় সেটি দেখি:
class Rock def wins_against?(other_move) other_move.do_you_beat_rock? end def do_you_beat_paper? false end def do_you_beat_scissors? true end end
লক্ষ্য করুন কেস স্টেটমেন্টটি চলে গেছে। এটিকে একটি একক মেথড কল এবং দুটি মেথড সংজ্ঞা দিয়ে রিপ্লেস করা হয়েছে।
আপডেট: কিছু পাঠক মন্তব্য করেছেন, আমি লজিক উল্টা হয়ে যাওয়া বিষয়টি লক্ষ্য করিনি এই প্যাটার্ন ইমপ্লিমেন্ট করার সময়। ড্যানিয়েল পি. ক্লার্কের প্রস্তাবিত একটি সমাধান হলো
playমেথডে অর্ডার ফ্লিপ করেmove2.wins_against?(move1)করা।
এটি কি অনেক ক্লিনার? আপনি কী মনে করেন?
আরেকটি মুভ!
এখন ধরুন আপনি একটি নতুন মুভ যোগ করতে চান। আপনাকে কী কী পরিবর্তন করতে হবে?
এক মিনিট চিন্তা করুন…
কেস স্টেটমেন্ট অ্যাপ্রোচে আপনাকে প্রতিটি মুভে একটি নতুন ব্রাঞ্চ যোগ করতে হবে। লক্ষ্য করুন আপনি একটি ভালোভাবে কাজ করা মেথডকে "বাধ্য" হচ্ছেন নতুন ফাংশন্যালিটি যোগ করার জন্য পরিবর্তন করতে।
কিন্তু আমাদের আরও OOP-ওরিয়েন্টেড ভার্সনে সেটি ইস্যু নয়। আমাদের শুধু নতুন মেথডগুলো যোগ করতে হবে। এটি ওপেন/ক্লোজড প্রিন্সিপল (SOLID-এ "O") কাজে লাগছে।
আরেকটি অপশন হতে পারে মেটাপ্রোগ্রামিং ব্যবহার ( method_missing বা define_method দিয়ে)।
আমি কি আসলে এর জন্য মেটাপ্রোগ্রামিং ব্যবহার করব? সম্ভবত না, যদি না মুভের সংখ্যা συνεχে পরিবর্তন হয়, অথবা মুভের সংখ্যা খুব বেশি থাকে।
মেটাপ্রোগ্রামিং-এর একটি খরচ আছে, এটি কিছু মানুষ যেন সিল्वर বুলেট মনে করে সেটি নয়। আপনি পারফরম্যান্স এবং পাঠযোগ্যতা বিনিময় করছেন একটু এক্সট্রা নমনীয়তার জন্য।
উপসংহার
এই নিবন্ধে আপনি শিখেছেন যে আপনার ক্লাস টাইপ চেক করার জন্য কেস স্টেটমেন্ট ব্যবহার এড়িয়ে চলা উচিত। পরিবর্তে, আপনাকে পলিমরফিজম-র সুবিধা নেওয়া উচিত।
এটি আপনাকে আরও ভালো কোড তৈরি করতে সাহায্য করবে যেটি নতুন কোড যোগ করে এক্সটেন্ড করা যায় বিদ্যমান কোড পরিবর্তন করার বদলে। এখন আপনার পালা অ্যাকশন নেওয়া এবং কিছু রিফ্যাক্টরিং করা 🙂
বটওয়ে এটা মানে নয় আমি আপনার টুলবক্স থেকে পুরোপুরি কেস স্টেটমেন্ট সরাতে সমর্থন করছি, কিন্তু আপনাকে সতর্ক থাকা উচিত যখনই আপনি একটি লিখছেন। নিশ্চিত করুন সেটি সমস্যার সেরা সমাধান।
আমি এ ধরণের আর্টিকেল লিখতে থাকি সেটি চাইলে এই আর্টিকেল শেয়ার করা না ভুলেন!