আমার সাম্প্রতিক নিবন্ধে, আমি Rails 5.1-এ একটি দুর্দান্ত নতুন বৈশিষ্ট্য উল্লেখ করেছি, delegate_missing_to
. এর সাথে delegate_missing_to
, যে কোনো পদ্ধতি যা আপনি একটি অবজেক্টে খুঁজে পাচ্ছেন না তাকে অন্য বস্তুতে বলা হয়, পরিবর্তে :
class Player
delegate_missing_to :@user
def initalize(user)
@user = user
end
def points
Game.points_for_user(user.id)
end
end
Player.new(user).name # calls user.name
কিন্তু, মন্তব্যে উল্লিখিত গেভিনের মতো, এটি উত্তরাধিকার এড়ানোর একটি অদ্ভুত উপায় বলে মনে হচ্ছে। কেন শুধু একটি সাবক্লাস ব্যবহার করবেন না? আপনি একই প্রভাব পাবেন, এবং আপনাকে সম্পূর্ণ নতুন বৈশিষ্ট্য যোগ করতে হবে না। এটা যোগ করা একটি অদ্ভুত জিনিস মত মনে হচ্ছে.
delegate_missing_to
কারণ থাকতে হবে যদিও যোগ করা হয়েছিল। এবং রেল বৈশিষ্ট্যগুলির জন্য, পুল অনুরোধগুলি সেই কারণগুলি খুঁজে বের করার একটি দুর্দান্ত উপায়। এই পুল অনুরোধে, DHH উল্লেখ করেছেন যে কেন তিনি এই বৈশিষ্ট্যটির পরামর্শ দিয়েছেন:
আপনি যদি ডেকোরেটর তৈরি করতে চান তবে এখানে একটি সাধারণ প্যাটার্ন রয়েছে:
এটি খনন শুরু করার জন্য একটি সুন্দর জায়গা বলে মনে হচ্ছে৷
কেন ডেকোরেটর?
যখন আপনি একটি ডেকোরেটর তৈরি করেন, তখন আপনি একটি নতুন সাবক্লাস তৈরি না করেই একটি বস্তুর কাজ করার পদ্ধতি পরিবর্তন করেন৷ উদাহরণস্বরূপ, আগের থেকে কোডে:
class Player
delegate_missing_to :@user
def initalize(user)
@user = user
end
def points
Game.points_for_user(user.id)
end
end
আপনি বলবেন যে “খেলোয়াড় সজ্জা করে ব্যবহারকারী," কারণ একজন খেলোয়াড় প্রায় একটি ব্যবহারকারীর মত কাজ করে, কিন্তু একটি অতিরিক্ত পদ্ধতি আছে, points
. এবং এটি উত্তরাধিকার ছাড়াই করে।
কেন আপনি এই মত কিছু প্রয়োজন হবে? এটি একটি কঠিন প্রশ্নের উত্তর, কারণ অনেক ডিজাইন প্যাটার্নের মতো, এটা সবসময় পরিষ্কার নয় যে আপনি অন্য কিছুর পরিবর্তে এটি কোথায় ব্যবহার করতে চান।
আপনি কখন ডেকোরেটর ব্যবহার করবেন?
ডেকোরেটরগুলি উত্তরাধিকারের জন্য আরও জটিল উপায় হতে পারে। মানে, কোডের এই দুটি লাইনের মধ্যে কোনটি ভালো?
player = Player.new(User.new(name: "Justin")) # Player decorates User
player = Player.new(name: "Justin") # Player subclasses User
স্পষ্টতই দ্বিতীয়টি, তাই না? এখানে, সাবক্লাসের পরিবর্তে প্লেয়ারকে ডেকোরেটর হিসাবে তৈরি করা শুধুমাত্র কোডের অপচয়।
কিন্তু কখনও কখনও, আপনি যেখান থেকে অবজেক্টটি তৈরি করেছেন তার থেকে অনেক দূরে একটি অবজেক্টে পরে কার্যকারিতা যোগ করতে চান৷ উদাহরণস্বরূপ, আপনার যদি এইরকম কোড থাকত?
user = User.find(1)
... some time later ...
player = Player.new(user)
এখন, আপনি আপনার ইচ্ছামত ব্যবহারকারী তৈরি করতে পারেন, আপনি যে পদ্ধতিতে চান। যে কোডটি ব্যবহারকারী অবজেক্ট তৈরি করে তা জানে না বা যত্ন করে না যে একটি প্লেয়ার ক্লাস এমনকি বিদ্যমান। এবং আপনি যদি সেই অতিরিক্ত পদ্ধতিগুলি আর না চান তবে আপনি এখনও মূল ব্যবহারকারী অবজেক্ট ব্যবহার করতে পারেন৷
৷এটি আপনাকে আচরণকে বিভিন্ন শ্রেণিতে আলাদা করতে সাহায্য করে। প্রতিটি শ্রেণী একটি নির্দিষ্ট পরিস্থিতিতে ব্যবহারকারী অবজেক্টটি কীভাবে ব্যবহার করা হবে তার উপর ফোকাস করতে পারে - একজন খেলোয়াড়, একজন কর্মচারী, একজন বিকাশকারী। উত্তরাধিকারের সাথে, এই সমস্ত জিনিসগুলিকে একত্রিত করা সহজ৷
৷মিস্টার ক্রিস মন্তব্যে ডেকোরেটরদের আরেকটি সুবিধা উল্লেখ করেছেন:
আপনি যখন একটি বস্তু সাজাইয়া, আপনি শুধুমাত্র সেই বস্তুর পাবলিক পদ্ধতি কল করতে পারেন. যখন আপনি সাবক্লাস করেন, আপনি যেকোনো পদ্ধতিতে কল করতে পারেন, এমনকি ব্যক্তিগতও। এটি সাবক্লাসগুলিকে আরও ঘন ঘন ভাঙতে পারে, কারণ তারা দুর্ঘটনাক্রমে তাদের পিতামাতার বাস্তবায়নের বিবরণের উপর নির্ভর করতে পারে। এই বিবরণগুলি সাধারণত পাবলিক পদ্ধতির চেয়ে বেশি পরিবর্তিত হবে৷
আপনি যখন বড় ক্লাসগুলিকে আলাদা করছেন তখন ডেকোরেটরগুলি বিশেষভাবে কার্যকর হতে পারে। ডেকোরেটরদের সাথে, একক-দায়িত্ব নীতি অনুসরণ করা সহজ – প্রতিটি ডেকোরেটর একটি জিনিস করতে পারে এবং এটি ভালভাবে করতে পারে এবং আপনি আরও জটিল আচরণ পেতে ডেকোরেটরকে একত্রিত করতে পারেন।
রুবিতে আচরণ ভাগ করে নেওয়ার অনেক উপায় রয়েছে। আপনি সাবক্লাস করতে পারেন, আপনি মডিউলগুলিকে একত্রিত করতে পারেন, আপনি এমনকি একটি ক্লাস থেকে পদ্ধতিগুলি ধরতে পারেন এবং আপনি চাইলে অন্যটির সাথে সংযুক্ত করতে পারেন। ডেকোরেটর প্যাটার্ন, যদিও, আপনাকে একটু ভিন্ন কিছু দেয়। আপনি শুধু ইন্সট্যান্স ভেরিয়েবল এবং মেথড কল ব্যবহার করছেন, যে কোনো অবজেক্ট-ওরিয়েন্টেড ভাষার বিল্ডিং ব্লক। এই মৌলিক বিষয়গুলি থেকে, আপনার অ্যাপটি চলাকালীন আপনি নমনীয় আচরণ করতে পারেন - আপনার কোডকে অতিরিক্ত জটিলতা ছাড়াই৷