কম্পিউটার টিউটোরিয়াল

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উইকিপিডিয়া অনুযায়ী, অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিং (OOP) হলো একটি প্রোগ্রামিং প্যারাডাইম যা "অবজেক্ট" কনসেপ্টের ওপর ভিত্তি করে, যেটি ডেটা এবং কোড 두নো ধারণ করতে পারে: ডেটা ফিল্ডস আকারে (যাকে প্রায়শই অ্যাট্রিবিউট বা প্রোপার্টি বলা হয়) এবং কোড প্রসিডিউরস আকারে (যাকে প্রায়শই মেথড বলা হয়)।

রুবি একটি পিউর অবজেক্ট-ওরিয়েন্টেড ল্যাঙ্গুয়েজ, যার মানে রুবি ল্যাঙ্গুয়েজে সব কিছু একটি অবজেক্ট। এই অবজেক্টগুলো,চাহে সেগুলো স্ট্রিং, নাম্বার, ক্লাস, মডিউল, ইত্যাদি হোক, একটি সিস্টেমে অপারেট করে যাকে দ্য অবজেক্ট মডেল (The Object Model) বলা হয়।

রুবি একটি মেথড অফার করে যেটি object_id নামে পরিচিত, যা সকল অবজেক্টের জন্য উপলব্ধ। এই আইডেন্টিফায়ার একটি ইন্টিজার রিটার্ন করে এবং যেকোনো দুটি অবজেক্টের জন্য কখনো একই হয় না। চলুন irb-এ যেতে হাতে খড়ি দিয়ে; আপনি এটি করতে পারেন আপনার টার্মিনালে irb টাইপ করে।

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানোanusারে, স্ট্রিং, ইন্টিজার, অ্যারে, ক্লাস, এবং মেথড পর্যন্ত—সবে অবজেক্ট, কারণ তাদের object ID রয়েছে।

এই আর্টিকেলে, আমরা নিচের কনসেপ্টগুলো বিস্তারিত কভার করব:

  • ক্লাস এবং ইনস্ট্যান্স (Classes and instances)
  • ইনহেরিটেন্স (Inheritance)
  • পাবলিক, প্রাইভেট, এবং প্রটেক্টেড মেথডস
  • মিক্সিনস (Mixins)
  • মডিউলস (Modules)
  • অবজেক্ট হায়ারার্কি (Object hierarchy)

ক্লাস এবং ইনস্ট্যান্স

রুবিতে, ক্লাসগুলো হলো যেখানে একটি অবজেক্টের অ্যাট্রিবিউট এবং অ্যাটিচুড (অ্যাকশন) ডিফাইন করা হয়। যদি একটি অবজেক্ট গোলাকার হয় (একটি অ্যাট্রিবিউট) এবং বলতে পারে (একটি অ্যাকশন), আমরা সেটি ক্লাস থেকে বুঝতে পারি কারণ এই অ্যাট্রিবিউট এবং অ্যাকশনগুলো সে ক্লাসে মেথড হিসেবে ডিফাইন করা থাকে। একটি ক্লাসের Angehörী একটি অবজেক্টকে সেই ক্লাসের একটি ইনস্ট্যান্স বলা হয় এবং .new ব্যবহার করে তৈরি (instantiated) হয়। চলুন Human নামে একটি ক্লাস তৈরি করি। আমরা সবাই মানব, তাই এটি মজার হবে।

class Human
  def initialize(name)
    @name = name
  end
end

initialize মেথড একটি ক্লাসের নতুন ইনস্ট্যান্স তৈরি করার জন্য রিকোয়ারমেন্টস আইডেন্টিফাই করে। উপরের কেসে, আমরা দেখতে পাচ্ছি যে একটি নতুন মানব তৈরির জন্য একটি নাম রিকোয়ারড। অতএব, একটি নতুন হিউম্যান ইনস্ট্যান্স তৈরি করা যায় Human.new(name) কমান্ড দিয়ে, যেখানে নাম আপনার পছন্দ। আমাদের কেসে, চলুন 'Henry' ব্যবহার করি। আমাদের irb এনভায়রনমেন্টে এটি টেস্ট করতে, আমাদের যা করতে হবে সেটি হলো ফাইলটি লোড করা load './path_to_filename' কমান্ড দিয়ে এবং ফাইল রি-এক্সিকিউশনের জন্য কমান্ডটি পুনরাবৃত্তি করা যখনই পরিবর্তন করা হয়। আমার কেসে, এটি load './Human.rb' কারণ irb সেই ফোল্ডারে খুলা আছে যেটিতে সে ফাইল আছে। irb ছাড়া কোড চালানোর জন্য, আমাদের প্রতিটি কমান্ডের আগে puts স্টেটমেন্ট যোগ করতে হবে যাতে রেজাল্ট видиবল হয়।

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

যখন আমরা একটি নাম ছাড়া একটি নতুন হিউম্যান তৈরি করার চেষ্টা করি, আমরা একটি আর্গুমেন্ট এরর পাই কারণ নাম রিকোয়ারড। যাইহোক, যখন আমরা সঠিকভাবে করি, আমরা দেখি যে Henry নামে মানবটি তৈরি হয়েছে এবং Human ক্লাসের অন্তর্গত। Henry অতএব Human ক্লাসের একটি ইনস্ট্যান্স।

@name ভেরিয়েবলকে ইনস্ট্যান্স ভেরিয়েবল বলা হয় কারণ এটি @ সিম্বল দিয়ে শুরু হয়, যার মানে এই ভেরিয়েবল ক্লাসের যেকোনো অন্য মেথড দ্বারা রেফারেন্স করা যাবে, যতক্ষণ না ক্লাস ইনস্ট্যান্সটি একজিস্ট করে। এখানে, আমরা এটি তৈরি করেছি এবং এটি সেট করেছি সেই নামের সাথে যেটি অবজেক্টটি ইনিশিয়ালাইজড হয়েছিল।

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

def name
  @name
end

def no_of_legs
  2
end

def no_of_hands
  2
end

def speak
  'blablabla'
end

আমরা মেথড যোগ করেছি যা তৈরি হওয়া মানবের নাম রিট্রিভ করে, মানবের পা এবং হাতের সংখ্যা ডিফাইন করে, এবং মানবকে কথা বলার ক্ষমতা দেয়। আমরা এই মেথডগুলো ক্লাস ইনস্ট্যান্সে কল করতে পারি instance.method_name ব্যবহার করে, নিচে দেখানো अनुसार।

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

ক्या होगा যদি আমরা আমাদের মন পরিবর্তন করি এবং আমাদের ক্লাস ইনস্ট্যান্স Henry-এর নাম পরিবর্তন করতে চাই? রুবিতে একটি বিল্ট-ইন মেথড রয়েছে যা এটি করতে পারে, কিন্তু এটি ম্যানুয়ালিও করা যায়। ম্যানুয়ালি, আমরা আমাদের name মেথডকে শুধু একটি গেটার মেথড (যেটি নাম পায়) থেকে একটি সেটার মেথডেও পরিবর্তন করতে পারি যা ভ্যালু সেট করবে যদি প্রদান করা হয়।

def name=(new_name)
  @name = new_name
end

রুবির বিল্ট-ইন attr_accessor মেথড ব্যবহার করে, আমরা আমাদের name মেথড ডিসকার্ড করতে পারি এবং এটিকে লাইন attr_accessor :name দিয়ে রিপ্লেস করতে পারি:

class Human
  attr_accessor :name
  def initialize(name)
    @name = name
  end
  # rest of the code
end

যে পদ্ধতিটিই বেছে নেওয়া হোক, একদিন শেষে, এটি হলো যা প্রাপ্য।

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

এতক্ষণে তৈরি সকল মেথডগুলো instance methods নামে ডাকা হয় কারণ এগুলো ক্লাসের যেকোনো ইনস্ট্যান্সে কল করা যায় কিন্তু ক্লাসে সরাসরি নয়। এছাড়া একটি জিনিস রয়েছে যাকে class method বলা হয়, যা ক্লাসে সরাসরি কল করা যায় কিন্তু এর ইনস্ট্যান্সগুলিতে নয়। ক্লাস মেথডের নাম মেথড নামের আগে self. প্রিফিক্স দিয়ে দেয়া হয়। একটি উদাহরণ:

# Human ক্লাসের ভিতরে
def self.introduction
  "I am a human, not an alien!"
end

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানো अनुसार, ক্লাস মেথড শুধু ক্লাসটিই এক্সেস করতে পারে, এর ইনস্ট্যান্সগুলো নয়। এছাড়া, যেন ইনস্ট্যান্স ভেরিয়েবল থাকে, তেমনি ক্লাস ভেরিয়েবল রয়েছে, যেগুলো দুটি @ সিম্বল দিয়ে প্রিফিক্সড। একটি উদাহরণ নিচে দেখানো হলো।

class Human
  attr_accessor :name
  @@no_cars_bought = 0 # class variable
  def initialize(name)
    @name = name
  end
  def self.no_cars_bought
    @@no_cars_bought
  end
  def buy_car
    @@no_of_cars_bought += 1
    "#{@name} just purchased a car"
  end
end

এই উদাহরণে, আমরা একটি buy_car মেথড যোগ করেছি যাতে প্রতিটি মানব গাড়ি কিনতে পারে। আমরা একটি ক্লাস ভেরিয়েবল @@no_of_cars_bought তৈরি করেছি যা প্রতিবার গাড়ি কেনার সময় ১ বাড়ায়। শেষে, আমরা একটি ক্লাস মেথড no_cars_bought তৈরি করেছি যা কতগুলো গাড়ি কেনা হয়েছে সেটি ফেচ করে। চলুন দেখি কীভাবে এটি কাজ করে:

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

এতক্ষণে ডিফাইন করা সকল মেথড পাবলিক মেথড নামে পরিচিত কারণ সেগুলো ক্লাসের বাইরে থেকে এক্সেসযোগ্য। আমরা প্রাইভেট মেথডও ডিফাইন করতে পারি, যেগুলো শুধু ক্লাসের ভিতর থেকে এক্সেসযোগ্য। চলো একটি উদাহরণ 트াই করি।

# Human ক্লাসের নিচে
def say_account_number
  "My account number is #{account_number}"
end
private
def account_number
  "1234567890"
end

এটি নিচের রেজাল্ট দেয়:

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

যখন আমরা henry.account_number কল করি, আমরা একটি "NoMethodError" পাই কারণ account_number একটি প্রাইভেট মেথড যা শুধু ক্লাসের ভিতর থেকে এক্সেস করা যায়। যখন একই ক্লাসে থাকা say_account_number মেথড দিয়ে অ্যাক্সেস করি, কোনো এরর নেই। মনে রাখবেন যে private কীওয়ার্ডের পরের প্রতিটি ইনস্ট্যান্স মেথড একটি প্রাইভেট মেথড হয়ে যায়; তাই প্রাইভেট মেথডগুলো ক্লাসের নিচে সব পাবলিক মেথডের পর ডিফাইন করা উচিত।

আপনি কি প্রটেক্টেড মেথড সম্পর্কে শুনেছেন? হ্যাঁ, সেটিও রয়েছে! কিন্তু আমরা সেটি ইনহেরিটেন্স কনসেপ্ট বুঝার পর আলোচনা করব।

ইনহেরিটেন্স (বংশানুক্রম)

এখন আমরা ক্লাস এবং ইনস্ট্যান্স সম্পর্কে জানি, চলুন ইনহেরিটেন্স নিয়ে কথা বলি। ইনহেরিটেন্স কনসেপ্ট ভালোভাবে বুঝতে, চলুন Mammal নামে একটি নতুন ক্লাস তৈরি করি যেহেতু মানব প্রাণী (mammal)। আমি বিজ্ঞান শ্রেণির একটি फ्रেজ মনে করি: "সকল মানব প্রাণী, কিন্তু সকল প্রাণী মানব নয়"। আমি মনে করি প্রাণীদের কিছু বৈশিষ্ট্য হলো চুল বা লোম থাকা এবং জটিল মস্তিষ্ক থাকা। চলুন এই তথ্যগুলো Mammal ক্লাসে রাখি।

class Mammal
  def has_hair?
    "Most certainly, Yes"
  end
  def has_complex_brain?
    "Well, as a mammal, what do you expect?"
  end
end

আপনি কি আমার বিজ্ঞান শ্রেণির ফ্রেজটি মনে করেন? যদি হ্যাঁ, তবে একটি রিলেশনশিপ তৈরি করা গুরুত্বপূর্ণ যা এই স্টেটমেন্টটি ভ্যালিডেট করে। তাহলে কী করব? আমরা হিউম্যান ক্লাসকে Mammal ক্লাসের প্রোপার্টি ইনহেরিট করার অনুমতি দেব < Mammal এড করে এর ক্লাস ডেফিনিশনে।

class Human < Mammal
  # all other code
end

যে ক্লাস অন্য ক্লাসের প্রোপার্টি ইনহেরিট করে, তাকে সাবক্লাস (subclass) বলা হয়, এবং যে ক্লাস থেকে ইনহেরিট করা হয়, তাকে সুপারক্লাস (superclass) বলা হয়। আমাদের কেসে, Human হলো সাবক্লাস এবং Mammal হলো সুপারক্লাস। এখানে নোট করা গুরুত্বপূর্ণ যে যদি আপনি সকল ক্লাস একই ফাইলে ডিফাইন করছেন যেন আমরা করছি, Mammal ক্লাস ডেফিনিশন Human ক্লাসের আগে আপনার ফাইলে থাকা উচিত, কারণ আমরা একটি ভেরিয়েবল রেফার করতে চাই না সেটি ডিফাইন হওয়ার আগে। চলুন দেখি মানবের এখন কী অ্যাডিশনাল ফিচার রয়েছে।

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানো अनुसार, মানবকে এখন Mammal ক্লাসে ডিফাইন করা সকল অ্যাট্রিবিউট এক্সেস পাওয়া যাচ্ছে। যদি আমরা ইনহেরিটেন্স রিমুভ করি (অর্থাৎ, সেই লাইন থেকে < Mammal রিমুভ করি) এবং কমান্ড henry.class.superclass চালাই, আমরা "Object" রেসপন্স পাব। এটি আমাদের বলে যে প্রতিটি ক্লাস যখন সরাসরি অন্য ক্লাস থেকে ইনহেরিট করে না, তার সুপারক্লাস "Object", যা আরও শক্তিশালী করে বলে যে রুবিতে, ক্লাসগুলোকেও অবজেক্ট।

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

এখন আমরা সুপারক্লাস সম্পর্কে জানি, এটি super কীওয়ার্ড নিয়ে কথা বলার পারফেক্ট টাইম। রুবি এই কীওয়ার্ড প্রদান করে সুপারক্লাসে ইতিমধ্যে বিদ্যমান মেথডস পুনরাবৃত্তি এবং মডিফাই করতে। আমাদের Mammal সুপারক্লাসে, মনে করুন আমাদের একটি মেথড রয়েছে has_hair? নামে; কী হবে যদি আমরা সেই মেথড কল হলে মানব-স্পেসিফিক কিছু অতিরিক্ত ইনফরমেশন যোগ করতে চাই? এখানেই super কীওয়ার্ডের ব্যবহার আসল। আমাদের Human ক্লাসে, আমরা একই নামের একটি মেথড ডিফাইন করি, has_hair?।

def has_hair?
  super + ", but humans can be bald at times"
end

যখন super কীওয়ার্ড কল করা হয়, রুবি সুপারক্লাসে সেই মেথড নামটি খোঁজে এবং এর রেজাল্ট রিটার্ন করে। উপরের মেথডে, আমরা সুপারক্লাসের has_hair? মেথডের প্রোডিউসড রেজাল্টে কিছু এক্সট্রা ইনফরমেশন যোগ করেছি।

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

রুবি শুধু সিঙ্গেল ক্লাস ইনহেরিটেন্স সাপোর্ট করে, যার মানে আপনি শুধু একটি ক্লাস থেকে ক্লাস প্রোপার্টি ইনহেরিট করতে পারেন। আমি নিশ্চিত আপনি চিন্তা করছেন কী হবে যদি আপনি একাধিক প্রোপার্টি যোগ করতে চান যেগুলো একটি নির্দিষ্ট ক্লাসে স্পেসিফিক নয়। রুবি এর জন্যও ব্যবস্থা করে রেখেছে মিক্সিনস (mixins) আকারে, কিন্তু তার আগে চলুন প্রটেক্টেড মেথডস নিয়ে কথা বলি।

প্রটেক্টেড মেথডস

প্রটেক্টেড মেথডস প্রাইভেট মেথডের মতো কাজ করে যাতে সেগুলো একটি ক্লাস এবং এর সাবক্লাসের ভিতরে কল করা যায়। চলুন Mammal ক্লাসে একটি প্রটেক্টেড মেথড তৈরি করি।

# Mammal ক্লাসের নিচে
def body_status
  body
end
protected
def body
  "This body is protected"
end

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানো अनुसार, আমরা body মেথড এক্সেস করতে পারি না কারণ এটি প্রটেক্টেড। যাইহোক, আমরা এটি body_status মেথড দিয়ে এক্সেস করতে পারি, যা Mammal ক্লাসের ভিতরেই একটি অন্য মেথড। আমরা প্রটেক্টেড মেথডগুলো সাবক্লাস থেকে এক্সেস করতে পারি যেখানে এটি ডিফাইন করা হয়েছে। চলুন Human ক্লাসে এটি ট্রাই করি।

# Human ক্লাসের ভিতরে
def check_body_status
  "Just a human checking that " + body.downcase
end

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানো অনুযায়ী, রেগার্ডলেস body মেথড Human ক্লাসে ডিফাইন করা হয়েছে এবং প্রটেক্টেড, Human ক্লাস এটি এক্সেস করতে পারে কারণ এটি Mammal ক্লাসের একটি সাবক্লাস। এই সাবক্লাস অ্যাক্সেস প্রাইভেট মেথডসের জন্যও সম্ভব; যাইহোক, এটি প্রশ্ন উপস্থাপন করে এই মেথডগুলোর মধ্যে পার্থক্য কী।

প্রটেক্টেড মেথডস এক্সপ্লিসিট রিসিভার দিয়ে কল করা যায়, যেন receiver.protected_method, যতক্ষণ না রিসিভার যেন self কীওয়ার্ড বা self এর সেম ক্লাসে থাকে। কিন্তু প্রাইভেট মেথড শুধু এক্সপ্লিসিট রিসিভার দিয়ে কল করা যায় যখন এক্সপ্লিসিট রিসিভার self হয়। চলুন আমাদের কোড এডিট করি body.downcase কে self.body.downcase দিয়ে রিপ্লেস করে check_body_status মেথডে এবং আমাদের প্রাইভেট মেথড কলটিও self সহ পরিবর্তন করি।

def check_body_status
  "Just a human checking that " + self.body.downcase # body method is protected
end
def say_account_number
  "My account number is #{self.account_number}" # account_number method is private
end

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

P.S.: Ruby 2.7 এর আগে, একটি প্রাইভেট মেথড কল করলে ইনফরমেশন পাওয়ার জন্য self ব্যবহার করা অসম্ভব ছিল।

চলুন self শব্দটি একই ক্লাসের একটি অবজেক্ট দিয়ে রিপ্লেস করি। আমাদের কেসে, self হলো Henry, যিনি মেথডগুলো কল করছেন, এবং Henry হলো Human ক্লাসের একটি ইনস্ট্যান্স, যা Mammal ক্লাস থেকে ইনহেরিট করেছে।

def check_body_status
  non_self = Human.new('NotSelf') #same class as self
  puts "Just #{non_self.name} checking that " + non_self.body.downcase
  # Mammal.new is also in the same class as self
  "Just a human checking that " + Mammal.new.body.downcase
end
def say_account_number
  non_self = Human.new('NotSelf')
  "My account number is #{non_self.account_number}"
end

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানো অনুযায়ী, প্রটেক্টেড মেথডসে self কে self এর সেম ক্লাসের একটি অবজেক্ট দিয়ে রিপ্লেস করা সম্ভব, কিন্তু প্রাইভেট মেথডসে এটি অসম্ভব।

মিক্সিনস (Mixins)

মিক্সিনস হলো একটি মডিউল-এ ডিফাইন করা কোডের সেট, যা যখন কোনো ক্লাসে ইনক্লুড বা এক্সটেন্ড করা হয়, সেই ক্লাসে অতিরিক্ত ক্যাপাবিলিটি প্রদান করে। সíngল ক্লাস ইনহেরিটেন্সের মতো নয়, কতগুলো মডিউল একসাথে একটি ক্লাসে যোগ করা যায়, এর কোনো লিমিট নেই। এই ইনফরমেশনের আলোকে, চলুন Movement নামে একটি মডিউল তৈরি করি যাতে হিউম্যান ক্লাসে মובמেন্ট অ্যাবিলিটি যোগ করা যায়।

module Movement
  def hop
    "I can hop"
  end
  def swim
    "Ermmmm, I most likely can if I choose"
  end
end

পরবর্তী ধাপ হবে এই মডিউলটি আমাদের Human ক্লাসে ইনক্লুড করা। এটি করা হয় include ফ্রেজটি কওয়েশনশন klas添加。 আমাদের কেসে, এটি হবে include Movement যোগ করা হিউম্যান ক্লাসে, নিচে দেখানো অনুযায়ী।

class Human < Mammal
  include Movement
  # rest of the code
end

এই কোডটি টেস্ট করি:

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানো অনুযায়ী, মডিউল দিয়ে মিক্স করা মেথডগুলো শুধু ক্লাসের ইনস্ট্যান্সগুলোর জন্য উপলব্ধ, ক্লাসের জন্য নয়। কী হবে যদি আমরা মডিউলের মেথডগুলো ক্লাসে উপলব্ধ করতে চাই, ইনস্ট্যান্সে না? এটি করতে, আমরা "include" টার্মকে "extend" দিয়ে রিপ্লেস করব, যেন extend Movement।

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

.extend টার্মটি ক্লাস ইনস্ট্যান্সেও ব্যবহার করা যায় কিন্তু খুব ভিন্নভাবে। চলুন Parent নামে আরেকটি মডিউল তৈরি করি।

module Parent
  def has_kids?
    "most definitely"
  end
end

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানো অনুযায়ী, dad ভেরিয়েবলعلى .extend(Parent) ব্যবহার করলে has_kids? মেথডটি সেটি জন্য উপলব্ধ হয়ে যায়। এটি বিশেষভাবে উপকারী যখন আমরা চাই না মডিউলের মেথডগুলো প্রতিটি ক্লাস ইনস্ট্যান্সে মিক্স হয়। তাই, extend শুধু সেই নির্দিষ্ট ইনস্ট্যান্সে ব্যবহার করা যায় যেটিতে আপনি আগ্রহী।

মডিউলস (Modules)

মডিউলস হলো ক্লাস, মেথড, কনস্ট্যান্ট, এবং এমনকি অন্যান্য মডিউল 위한 হাউজিং। মিক্সিনস হিসেবে ব্যবহারের পাশাপাশি, মডিউলসের অন্যান্য ব্যবহার রয়েছে। এগুলো আপনার কোড অর্গানাইজ করার একটি দুর্দান্ত উপায় যাতে নাম ক্ল্যাশ (name clashing) না হয়, কারণ এগুলো নেমস্পেসিং (namespacing) নামে একটি সুবিধা অফার করে। রুবিতে, প্রতিটি ক্লাস একটি মডিউল, কিন্তু কোনো মডিউল একটি ক্লাস নয়, কারণ মডিউলগুলো nici ইনস্ট্যানশিয়েট করা যায় nici ইনহেরিট করা যায়। নেমস্পেসিং বুঝতে, চলুন একটি মডিউল তৈরি করি যেটিতে একটি কনস্ট্যান্ট, একটি ক্লাস, একটি মেথড, এবং আরেকটি মডিউল রয়েছে।

module Male
  AGE = "Above 0"
  class Adult
    def initialize
      puts "I am an adult male"
    end
  end
  def self.hungry
    puts "There's no such thing as male food, I just eat."
  end
  module Grown
    def self.age
      puts "18 and above"
    end
  end
end

আপনি লক্ষ্য করেছেন হতে পারে যে মডিউলগুলোর ভিতরে ডিফাইন করা এবং কল করা মেথডগুলো self. দিয়ে প্রিফিক্সড। এর কারণ হলো মডিউলগুলো ইনস্ট্যানশিয়েট করা যায় না, এবং self. প্রিফিক্স ছাড়া যেকোনো মেথড শুধু মিক্সিন হিসেবে উপলব্ধ থাকবে, যেন আমরা আগে mixins আলোচনা করলাম। একটি মডিউলেই একটি মেথড কল করতে, আমাদের সেটি মেথড নামেই আইডেন্টিফাই করতে হবে self.method_name ব্যবহার করে। মনে রাখবেন যে আমরা self কীওয়ার্ড ক্লাস মেথডেও ব্যবহার করেছি; একই প্রিন্সিপল এখানেও কাজ করে।

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানো অনুযায়ী, একটি মডিউলের ভিতরে ডিফাইন করা ক্লাস, মডিউল, বা কনস্ট্যান্টে পৌঁছাতে, আমরা module_name::target_name ব্যবহার করি। নেমস্পেসিং কনসেপ্ট ভালোভাবে বুঝতে, আমরা আরেকটি মডিউল তৈরি করব যেটিতে একটি ক্লাস থাকবে Adult নামে, এবং তারপর আমরা দেখব কীভাবে দুটি ক্লাস ডিফারেনশিয়েট করা হয়।

module Female
  class Adult
    def initialize
      puts "I am an adult female"
    end
  end
  def self.hungry
    puts "Maybe there's such a thing as female food, I'm not sure. I just need to eat"
  end
end

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানো অনুযায়ী, আমাদের দুটি ক্লাস রয়েছে যাদের নাম "Adult"। এগুলো তাদের নিজস্ব মডিউলে র‍্যাপ করে, আমরা এই নামগুলো ব্যবহার করতে পারি কোনো কনফিউশন ছাড়া যে কোন Adult ক্লাস প্রতিবার কল করা হচ্ছে। উপরন্তু, আমাদের কোড আরও রিডেবল এবং অর্গানাইজড, এবং আমরা separation of concerns ডিজাইন প্রিন্সিপল ইম্প্লিমেন্ট করি, কারণ আমরা ভিন্ন কোড ব্লকগুলো ভিন্ন ক্যাটাগরিতে আলাদা করি তাদের ফাংশন অনুযায়ী।

অবজেক্ট হায়ারার্কি (Object Hierarchy)

ক্লাস, ইনস্ট্যান্স, মডিউল, এবং ইনহেরিটেন্স কনসেপ্ট বুঝতে পেরে ভালো লাগল, কিন্তু এই এলাকায় জ্ঞান অসম্পূর্ণ থাকবে রুবিতে অবজেক্ট হায়ারার্কি বুঝা ছাড়া। এটি রুবিতে একটি মেথড খুঁজে বের করার অর্ডারকে রেফার করে। কিছু মেথড রয়েছে যা আমাদের এই হায়ারার্কি বুঝতে সাহায্য করে; 그중 একটি হলো ancestors মেথড। এই মেথড ক্লাস ইনস্ট্যান্সের জন্য উপলব্ধ নয় কিন্তু ক্লাসগুলো এবং তাদের ancestor-রা কল করা যায়। একটি উদাহরণ নিচে দেখানো হলো।

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

Human.ancestors এর রেজাল্ট থেকে আমরা দেখি যে এই মেথড ক্লাসটি, এর ডিরেক্টলি ইনক্লুডেড মডিউলস, এর প্যারেন্ট ক্লাস, এবং প্যারেন্ট ক্লাসের ডিরেক্টলি ইনক্লুডেড মডিউলস রিটার্ন করে; এই লুপ চলতে থাকে যতক্ষণ না এটি Basic Object-এ পৌঁছায়, যা সকল অবজেক্টের রুট (root)।

একটি আরো মেথড রয়েছে ক্লাস সম্পর্কে আরো ইনফরমেশন পাওয়ার জন্য: included_modules মেথড।

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানো অনুযায়ী, হিউম্যান ক্লাসে দুটি মডিউল ইনক্লুডেড: একটি যা আমরা ডিরেক্টলি ইনক্লুড করেছি include Movement দিয়ে এবং অন্যটি যা Object ক্লাসে ইনক্লুডেড। এর মানে হলো প্রতিটি ক্লাস তার ancestor ক্লাস থেকে ক্লাস প্রোপার্টি ইনহেরিট করে, এবং তাদের মধ্যে ইনক্লুডেড প্রতিটি মডিউল সেটিও তাতে ইনক্লুড হয়। এই ইনফরমেশন ভিত্তিক, আমরা একটি সিম্পল এক্সারসাইজ করব রুবিতে মেথড লুকআপ পাথ (method lookup path) কনফার্ম করতে এবং কোন ক্লাসগুলো অন्योंের উপর প্রায়োরিটি পায় সেটি বুঝতে। আমরা একই নামে কিন্তু আলাদা আউটপুট স্ট্রিংয়ुक्त মেথড ডিফাইন করব Human ক্লাসে, Movement মডিউলে, এবং Mammal ক্লাসে।

# Mammal ক্লাসে
def find_path
  "Found me in the Mammal class path"
end
# Movement মডিউলে
def find_path
  "Found me in the Movement module path"
end
# Human ক্লাসে
def find_path
  "Found me in the Human class path"
end

এখন এই এক্সারসাইজটি করি।

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানো অনুযায়ী, যে অর্ডারে ancestor-রা লে-আউট করা হয় যখন আমরা একটি ক্লাসে .ancestors কল করি, সেটি পাথ যা ফলো করা হয় যখন একটি মেথড সে ক্লাসের ইনস্ট্যান্সে কল করা হয়। আমাদের তৈরি Human ক্লাস ইনস্ট্যান্সের জন্য, রুবি প্রথমে মেথডটি ক্লাসে খোঁজে; না পেলে, যেকোনো ডিরেক্টলি ইনক্লুডেড মডিউলে যাবে; না পেলে, সুপারক্লাসে যাবে এবং সাইকেলটি চলতে থাকবে যতক্ষণ না BasicObject-এ পৌঁছায়। যদি মেথড সেখানে ও না পাওয়া যায়, একটি "NoMethodError" রিটার্ন করা হয়। .ancestors মেথড ব্যবহার করে, আমরা একটি অবজেক্টের লুকআপ পাথ আইডেন্টিফাই করতে পারি এবং যেকোনো সময় এর মেথডগুলো কোথা থেকে আসছে সেটি বুঝতে পারি।

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

রুবির অবজেক্ট মডেলে গভীর ডাইভ: একটি কমপ্রিহেনসিভ গাইড

উপরে দেখানো অনুযায়ী, ভেরিয়েবল Henry-এ প্রচুর মেথড উপলব্ধ। যাইহোক, যখন আমরা সেগুলো Object ক্লাসে উপলব্ধ মেথডগুলো থেকে বিয়োগ করি, আমরা শুধু আমাদের স্পেসিফিক্যালি ডিফাইন করা মেথডগুলো পাই, এবং বাকি সব ইনহেরিটেড। এটি সকল অবজেক্ট, তার ক্লাস, এবং যেকোনো ancestor-র জন্য একই। বিনিশ্চিন্তে আপনার হাত গুঁড়িয়ে নিচের কন্বিনেশনগুলো ট্রাই করুন Human.methods, Mammal.methods, Module.methods, এবং আগে ডিফাইন করা সকল ক্লাস বা মডিউয়ের সাথে; আপনি পাবেন এটি আপনার রুবি অবজেক্ট মডেলের গ্রাস্প শক্তিশালী করে।

  1. AASM দিয়ে রুবিতে স্টেট মেশিন মাস্টার করুন: একটি প্র্যাক্টিক্যাল গাইড

  2. রুবিতে Dup বনাম Clone: অবজেক্ট কপি করার কৌশলকে মাস্টার করুন

  3. রুবি অবজেক্ট ডেকোরেটর প্যাটার্ন দিয়ে সমৃদ্ধ করুন: একটি প্র্যাক্টিক্যাল গাইড

  4. রুবির Freeze মেথড বোঝা: অবজেক্ট মিউটেবিলিটি ব্যাখ্যা