রুবি উত্তরাধিকার বনাম মিশিনস


127

রুবিতে, যেহেতু আপনি একাধিক মিশ্রণ অন্তর্ভুক্ত করতে পারেন তবে কেবল একটি শ্রেণি প্রসারিত করতে পারেন বলে মনে হচ্ছে উত্তরাধিকারের চেয়ে মিক্সিন পছন্দ করা হবে।

আমার প্রশ্ন: আপনি যদি কোডটি লিখছেন যা অবশ্যই কার্যকর হওয়ার জন্য প্রসারিত / অন্তর্ভুক্ত থাকতে হবে তবে কেন আপনি কখনও এটিকে একটি শ্রেণি বানাবেন? বা অন্য কোনও উপায়ে বলা, কেন আপনি সবসময় এটিকে একটি মডিউল বানাবেন না?

আপনি কেবল একটি শ্রেণি কেন চান তা কেবল একটি কারণেই আমি ভাবতে পারি এবং তা হল যদি আপনার ক্লাসটি ইনস্ট্যান্ট করার দরকার হয়। অ্যাক্টিভেকর্ড :: বেস এর ক্ষেত্রে, তবে আপনি কখনও এটিকে সরাসরি ইনস্ট্যান্ট করবেন না। সুতরাং এটি পরিবর্তে একটি মডিউল করা উচিত নয়?

উত্তর:


176

আমি কেবলমাত্র ওয়েল-গ্রাউন্ডেড রুবিস্টে (এইভাবে দুর্দান্ত বই) এই বিষয়টি সম্পর্কে পড়েছি । লেখক আমার ব্যাখ্যা করার চেয়ে ব্যাখ্যা করার চেয়ে ভাল কাজ করেছেন তাই আমি তাকে উদ্ধৃত করব:


কোনও একক নিয়ম বা সূত্র সর্বদা সঠিক নকশায় ফলাফল করে না। আপনি যখন ক্লাস-বনাম-মডিউল সিদ্ধান্ত নিচ্ছেন তখন বেশ কয়েকটি বিবেচনার বিষয়টি মাথায় রাখাই দরকারী:

  • মডিউলগুলির উদাহরণ নেই। এটি অনুসরণ করে যে সত্তা বা জিনিসগুলি সাধারণত ক্লাসে সর্বাধিক মডেল করা হয় এবং সত্ত্বা বা বিষয়গুলির বৈশিষ্ট্য বা বৈশিষ্ট্যগুলি মডিউলগুলিতে সর্বোত্তমভাবে থাকে ulated ধারাবাহিকভাবে, বিভাগ ৪.১.১ এ উল্লিখিত হিসাবে, শ্রেণীর নামগুলি বিশেষ্য হিসাবে দেখা যায়, যেখানে মডিউলের নামগুলি প্রায়শই বিশেষণ (স্ট্যাক বনাম স্ট্যাকলাইক) হয়।

  • একটি শ্রেণিতে কেবল একটি সুপারক্লাস থাকতে পারে তবে এটি এটি যতটা মডিউল চায় তার সাথে মিশতে পারে। যদি আপনি উত্তরাধিকার ব্যবহার করছেন তবে একটি বুদ্ধিমান সুপারক্লাস / সাবক্লাস সম্পর্ক তৈরি করতে অগ্রাধিকার দিন। ক্লাসটির এক এবং একমাত্র সুপারক্লাস সম্পর্কটিকে ব্যবহার না করে ক্লাসটির অনুমোদন দেওয়া যা বৈশিষ্ট্যের কয়েকটি সেটগুলির মধ্যে কেবল একটি হতে পারে।

এই বিধিগুলির একটি উদাহরণে সংক্ষেপণ, আপনার যা করা উচিত নয় তা এখানে:

module Vehicle 
... 
class SelfPropelling 
... 
class Truck < SelfPropelling 
  include Vehicle 
... 

বরং, আপনার এটি করা উচিত:

module SelfPropelling 
... 
class Vehicle 
  include SelfPropelling 
... 
class Truck < Vehicle 
... 

দ্বিতীয় সংস্করণ সত্তা এবং বৈশিষ্ট্যগুলি আরও অনেক ঝরঝরে করে মডেল করে। ট্রাক যানবাহন থেকে নেমে আসে (যার অর্থ উপলব্ধি হয়), যেখানে সেলফ্রোপেলিং যানবাহনের একটি বৈশিষ্ট্য (কমপক্ষে, আমরা বিশ্বের এই মডেলটিতে যাদের যত্ন করি তারা সবাই) — এমন একটি বৈশিষ্ট্য যা ট্রাকের বংশধর হওয়ার কারণে ট্রাকে চলে যায়, বা যানবাহন বিশেষায়িত ফর্ম।


1
উদাহরণটি এটিকে সুন্দরভাবে দেখায় - ট্রাক আইএস একটি যান - এমন কোনও ট্রাক নেই যা যানবাহন না হয়।
পিএল জে

1
উদাহরণটি এটি সুন্দরভাবে দেখায় - Truckআইএস এ Vehicle- Truckএমনটি নেই যা একটি হবে না Vehicle। তবে আমি মডিউলটি সম্ভবত কল করবো SelfPropelable(:?) হুম SelfPropeledশব্দ ঠিক আছে তবে এটি প্রায় একই: ডি। যাই হোক আমি এর মধ্যে অন্তর্ভুক্ত হবে না Vehicleকিন্তু Truck- যেমন আছে যানবাহন যে নন SelfPropeled। আরও ভাল ইঙ্গিতটি জিজ্ঞাসা করা হয় - অন্যান্য জিনিস আছে, যানবাহন না SelfPropeled? - বেশ সম্ভবত, তবে আমি খুঁজে পেতে আরও কঠিন হতে চাই। সুতরাং Vehicleসেলফপ্রোপেলিং ক্লাস থেকে উত্তরাধিকারী হতে পারে (শ্রেণি হিসাবে এটি হিসাবে এটি খাপ খায় না SelfPropeled- কারণ এটি একটি ভূমিকা আরও বেশি)
পিএল জে

39

আমি মনে করি মিক্সিনগুলি একটি দুর্দান্ত ধারণা, তবে এখানে আরও একটি সমস্যা রয়েছে যা এখানে কেউ উল্লেখ করেনি: নেমস্পেস সংঘর্ষগুলি। বিবেচনা:

module A
  HELLO = "hi"
  def sayhi
    puts HELLO
  end
end

module B
  HELLO = "you stink"
  def sayhi
    puts HELLO
  end
end

class C
  include A
  include B
end

c = C.new
c.sayhi

কোনটি জিতেছে? রুবিতে এটি পরেরটি হতে পারে module B, কারণ আপনি এটি পরে যুক্ত করেছিলেন module A। এখন, এই সমস্যাটি এড়ানো সহজ: নিশ্চিত হয়ে নিন যে সমস্ত module Aএবং module Bএর ধ্রুবক এবং পদ্ধতিগুলি অসম্ভব নেমস্পেসে রয়েছে। সমস্যাটি হ'ল সংঘর্ষগুলি ঘটলে সংকলক আপনাকে মোটেও সতর্ক করে না।

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


2
এটি সতর্কতার একটি বুদ্ধিমান শব্দ। সি ++ এর একাধিক উত্তরাধিকারের সমস্যাগুলির কথা মনে করিয়ে দেয়।
ক্রিস টোনকিনসন

1
এর জন্য কি কোনও ভাল প্রশান্তি রয়েছে? এটি পাইথনের একাধিক উত্তরাধিকারকে সর্বোত্তম সমাধান বলে কোনও কারণে মনে হচ্ছে (কোনও ভাষা পি * সিসিং ম্যাচ শুরু করার চেষ্টা না করা; কেবল এই নির্দিষ্ট বৈশিষ্ট্যের সাথে তুলনা করা)।
মার্সিন

1
@ বাজজ এটি দুর্দান্ত এবং সব কিছু, তবে বেশিরভাগ ভাষায় রচনা জটিল is এটি বেশিরভাগ ক্ষেত্রে হাঁসের প্রকারের ভাষায় প্রাসঙ্গিক। আপনি গৌরবময় রাজ্য না পাওয়ার গ্যারান্টিও দেয় না।
মার্সিন

পুরাতন পোস্ট, আমি জানি, কিন্তু এখনও অনুসন্ধানে সক্রিয়। উত্তরটি আংশিকভাবে ভুল - C#sayhiআউটপুটগুলি B::HELLOনয় কারণ রুবি ধ্রুবকগুলিকে মিশ্রিত করে, তবে রুবি ধ্রুবকগুলিকে দূর থেকে দূরে সরিয়ে দেয় - তাই HELLOরেফারেন্সে Bসর্বদা সমাধান হবে B::HELLO। এটি ক্লাস সি এর নিজস্বও নির্ধারিত থাকলেও এটি ধারণ C::HELLOকরে।
লাস

13

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


2
এটি প্রশ্নের সরাসরি উত্তর দেয়: উত্তরাধিকার একটি নির্দিষ্ট সাংগঠনিক কাঠামো প্রয়োগ করে যা আপনার প্রকল্পকে আরও পাঠযোগ্য করে তুলতে পারে।
এমেরি

10

আপনার প্রশ্নের উত্তর মূলত প্রাসঙ্গিক। পাব এর পর্যবেক্ষণ নিরসন করে, পছন্দটি প্রাথমিকভাবে বিবেচনাধীন ডোমেন দ্বারা চালিত হয়।

এবং হ্যাঁ, অ্যাক্টিভেকর্ডটি একটি সাবক্লাস দ্বারা প্রসারিত না করে অন্তর্ভুক্ত করা উচিত ছিল। অন্য একটি ওআরএম - ডেটাম্পার - স্পষ্টভাবে এটি অর্জন করে!


4

আমি অ্যান্ডি গ্যাসকেলের উত্তরটি খুব পছন্দ করি - কেবল এটি যুক্ত করতে চেয়েছিলাম হ্যাঁ, অ্যাক্টিভেকর্ডের উত্তরাধিকার ব্যবহার করা উচিত নয়, বরং কোনও মডেল / শ্রেণিতে আচরণ (বেশিরভাগ দৃ pers়তা) যুক্ত করার জন্য একটি মডিউল অন্তর্ভুক্ত করা উচিত। অ্যাক্টিভেকর্ড কেবলমাত্র ভুল দৃষ্টান্ত ব্যবহার করছে।

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

এটি দুঃখজনক যে, রেল সম্প্রদায়ের কেউই "রুবি উত্তরাধিকার" যেভাবে এটি ব্যবহার করার কথা বলেছিল তা ব্যবহার করছে না - শ্রেণি শ্রেণিবিন্যাসের সংজ্ঞা দেওয়ার জন্য, কেবল আচরণ যুক্ত করার জন্য নয়।


1

আমি মিশিনগুলি বোঝার সর্বোত্তম উপায় হ'ল ভার্চুয়াল ক্লাস। মিক্সিনগুলি হ'ল "ভার্চুয়াল ক্লাস" যা কোনও শ্রেণীর বা মডিউলের পূর্বপুরুষ চেইনে ইনজেকশন দেওয়া হয়েছিল।

আমরা যখন "অন্তর্ভুক্ত" ব্যবহার করি এবং এটি একটি মডিউল পাস করি তখন এটি পূর্বসূচী শৃঙ্খলে মডিউলটিকে ক্লাসের ঠিক আগে যোগ করে যা আমরা উত্তরাধিকার সূত্রে গ্রহণ করি:

class Parent
end 

module M
end

class Child < Parent
  include M
end

Child.ancestors
 => [Child, M, Parent, Object ...

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

module M
  def m
    puts 'm'
  end
end

class Test
end

Test.extend M
Test.m

আমরা সিঙ্গলটন_ক্লাস পদ্ধতিতে সিঙ্গলটন শ্রেণিতে অ্যাক্সেস করতে পারি:

Test.singleton_class.ancestors
 => [#<Class:Test>, M, #<Class:Object>, ...

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

module M
  def self.included(target)
    puts "included into #{target}"
  end

  def self.extended(target)
    puts "extended into #{target}"
  end
end

class MyClass
  include M
end

class MyClass2
  extend M
end

এটি এমন একটি আকর্ষণীয় প্যাটার্ন তৈরি করে যা বিকাশকারীরা ব্যবহার করতে পারেন:

module M
  def self.included(target)
    target.send(:include, InstanceMethods)
    target.extend ClassMethods
    target.class_eval do
      a_class_method
    end
  end

  module InstanceMethods
    def an_instance_method
    end
  end

  module ClassMethods
    def a_class_method
      puts "a_class_method called"
    end
  end
end

class MyClass
  include M
  # a_class_method called
end

আপনি দেখতে পাচ্ছেন যে, এই একক মডিউলটি উদাহরণ পদ্ধতিগুলি, "শ্রেণি" পদ্ধতিগুলি যুক্ত করছে এবং লক্ষ্য ক্লাসে সরাসরি অভিনয় করছে (এক্ষেত্রে a_class_method () কল করা)।

অ্যাক্টিভসপোর্ট :: উদ্বেগ এই প্যাটার্নটি encapsulates। অ্যাক্টিভসপোর্ট: কনসার্ন ব্যবহার করার জন্য এখানে একই মডিউলটি আবারও লেখা হয়েছে:

module M
  extend ActiveSupport::Concern

  included do
    a_class_method
  end

  def an_instance_method
  end

  module ClassMethods
    def a_class_method
      puts "a_class_method called"
    end
  end
end

-1

এখনই, আমি templateডিজাইনের ধরণ সম্পর্কে চিন্তা করছি । এটি একটি মডিউল দিয়ে ঠিক মনে হবে না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.