"হ্যালো বন্ধু!"

"হাই, বিলাবো!"

"আমাদের এখনও কিছু সময় বাকি আছে, তাই আমি আপনাকে আরও তিনটি নিদর্শন সম্পর্কে বলব।"

"আরো তিনজন? সব মিলিয়ে কয়জন আছে?"

"বর্তমানে কয়েক ডজন জনপ্রিয় নিদর্শন রয়েছে, তবে "সফল সমাধান" এর সংখ্যা সীমাহীন।"

"আমি দেখছি। তাই আমাকে কয়েক ডজন প্যাটার্ন শিখতে হবে?"

"যতক্ষণ না আপনার প্রকৃত প্রোগ্রামিং অভিজ্ঞতা না হয়, তারা আপনাকে অনেক কিছু দেবে না।"

"আপনি আরও একটু অভিজ্ঞতা লাভ করুন, এবং তারপরে, এক বছরের মধ্যে, এই বিষয়ে ফিরে আসুন এবং সেগুলিকে আরও গভীরভাবে বোঝার চেষ্টা করুন। কমপক্ষে কয়েক ডজন সবচেয়ে জনপ্রিয় ডিজাইনের নিদর্শন।"

"অন্য কারো অভিজ্ঞতা ব্যবহার না করা এবং তার পরিবর্তে 110 তম বার কিছু উদ্ভাবন করা একটি পাপ।"

"আমি রাজী."

"তাহলে শুরু করা যাক।"

অ্যাডাপ্টার (বা মোড়ানো) প্যাটার্ন

প্যাটার্নস: অ্যাডাপ্টার, প্রক্সি, ব্রিজ - 1

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

"প্রোগ্রামিং-এও একই রকম কিছু ঘটতে পারে। ক্লাস একই রকম কিন্তু ভিন্ন ইন্টারফেসে চলে। তাই আমাদের তাদের মধ্যে একটি অ্যাডাপ্টার তৈরি করতে হবে।"

"এই এটা দেখায় কিভাবে হয়:"

উদাহরণ
interface Time
{
 int getSeconds();
 int getMinutes();
 int getHours();
}

interface TotalTime
{
 int getTotalSeconds();
}

"ধরুন আমাদের দুটি ইন্টারফেস আছে: সময়  এবং  মোট সময় ।"

"টাইম ইন্টারফেস আপনাকে getSeconds (),  getMinutes () এবং  getHours () পদ্ধতি ব্যবহার করে বর্তমান সময় পেতে দেয় ।"

" টোটালটাইম ইন্টারফেস আপনাকে মধ্যরাত থেকে বর্তমান মুহুর্ত পর্যন্ত সেকেন্ডের সংখ্যা পেতে দেয়।"

"আমাদের যদি টোটালটাইম অবজেক্ট থাকে তবে আমাদের কি করা উচিত, কিন্তু আমাদের একটি টাইম অবজেক্ট বা তার বিপরীতে প্রয়োজন?"

"আমরা এর জন্য অ্যাডাপ্টার ক্লাস লিখতে পারি। যেমন:"

উদাহরণ
class TotalTimeAdapter implements Time
{
 private TotalTime totalTime;
 public TotalTimeAdapter(TotalTime totalTime)
 {
  this.totalTime = totalTime;
 }

 int getSeconds()
 {
  return totalTime.getTotalSeconds() % 60; // seconds
 }

 int getMinutes()
 {
  return totalTime.getTotalSeconds() / 60; // minutes
 }

 int getHours()
 {
  return totalTime.getTotalSeconds() / (60 * 60); // hours
 }
}
ব্যবহার
TotalTime totalTime = TimeManager.getCurrentTime();
Time time = new TotalTimeAdapter(totalTime);
System.out.println(time.getHours() + " : " + time.getMinutes () + " : " +time.getSeconds());

"এবং অন্য দিকে একটি অ্যাডাপ্টার:"

উদাহরণ
class TimeAdapter implements TotalTime
{
 private Time time;
 public TimeAdapter(Time time)
 {
  this.time = time;
 }

 int getTotalSeconds()
 {
  return time.getHours() * 60 * 60 + time.getMinutes() * 60 + time.getSeconds();
 }
}
ব্যবহার
Time time = new Time();
TotalTime totalTime = new TimeAdapter(time);
System.out.println(time.getTotalSeconds());

"আহ. আমি এটা পছন্দ করি. কিন্তু কোন উদাহরণ আছে?"

"অবশ্যই! একটি উদাহরণ হিসাবে, InputStreamReader হল একটি ক্লাসিক অ্যাডাপ্টার৷ এটি একটি InputStream কে একটি পাঠকে রূপান্তর করে৷"

"কখনও কখনও এই প্যাটার্নটিকে একটি মোড়কও বলা হয়, কারণ নতুন ক্লাস অন্য বস্তুকে 'মোড়ানো' করে।"

"আপনি এখানে কিছু অন্যান্য আকর্ষণীয় জিনিস পড়তে পারেন ।"

প্রক্সি প্যাটার্ন

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

"উদাহরণ স্বরূপ:"

আসল ক্লাসের ইন্টারফেস
interface Bank
{
 public void setUserMoney(User user, double money);
 public int getUserMoney(User user);
}
মূল শ্রেণীর বাস্তবায়ন
class CitiBank implements Bank
{
 public void setUserMoney(User user, double money)
 {
  UserDAO.updateMoney(user, money);
 }

 public int getUserMoney(User user)
 {
  return UserDAO.getMoney(user);
 }
}
প্রক্সি ক্লাস বাস্তবায়ন
class BankSecurityProxy implements Bank
{
 private Bank bank;
 public BankSecurityProxy(Bank bank)
 {
  this.bank = bank;
 }
 public void setUserMoney(User user, double money)
 {
  if (!SecurityManager.authorize(user, BankAccounts.Manager))
  throw new SecurityException("User can’t change money value");

  bank.setUserMoney(user, money);
 }

 public int getUserMoney(User user)
 {
  if (!SecurityManager.authorize(user, BankAccounts.Manager))
  throw new SecurityException("User can’t get money value");

  return bank.getUserMoney(user);
 }
}

"উপরের উদাহরণে, আমরা ব্যাঙ্ক ইন্টারফেস এবং সিটিব্যাঙ্ক ক্লাস বর্ণনা করেছি, এই ইন্টারফেসের একটি বাস্তবায়ন।"

"ইন্টারফেসটি আপনাকে ব্যবহারকারীর অ্যাকাউন্ট ব্যালেন্স পেতে বা পরিবর্তন করতে দেয়।"

এবং তারপরে আমরা BankSecurityProxy তৈরি করেছি , যা ব্যাঙ্ক ইন্টারফেসকেও প্রয়োগ করে এবং একটি ভিন্ন ব্যাঙ্ক ইন্টারফেসের একটি রেফারেন্স সংরক্ষণ করে। এই ক্লাসের পদ্ধতিগুলি ব্যবহারকারী অ্যাকাউন্টের মালিক নাকি ব্যাঙ্ক ম্যানেজার কিনা তা পরীক্ষা করে। যদি এটি না হয়, তাহলে একটি নিরাপত্তা ব্যতিক্রম নিক্ষেপ করা হয়।"

"এটি অনুশীলনে কীভাবে কাজ করে তা এখানে:"

নিরাপত্তা চেক ছাড়া কোড :
User user = AuthManager.authorize(login, password);
Bank bank = BankFactory.createUserBank(user);
bank.setUserMoney(user, 1000000);
নিরাপত্তা চেক সহ কোড :
User user = AuthManager.authorize(login, password);
Bank bank = BankFactory.createUserBank(user);
bank = new BankSecurityProxy(bank);
bank.setUserMoney(user, 1000000);

"প্রথম উদাহরণে, আমরা একটি ব্যাঙ্ক অবজেক্ট তৈরি করি এবং সেটিকে সেট ইউজারমনি পদ্ধতি বলি৷

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

"কুল!"

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

"আরও কী... এই সমস্ত চেইন অবজেক্টের সৃষ্টিকে একটি BankFactory ক্লাসে রাখা যেতে পারে, যেখানে আপনি আপনার প্রয়োজনীয় জিনিসগুলিকে সক্ষম/অক্ষম করতে পারেন।"

" BufferedReader একই নীতি ব্যবহার করে কাজ করে। এটি একটি Reader , কিন্তু এটি অতিরিক্ত কাজ করে।"

"এই পদ্ধতিটি আপনাকে বিভিন্ন «টুকরা» থেকে প্রয়োজনীয় কার্যকারিতা সহ একটি বস্তুকে «একত্রিত করতে» দেয়।"

"ওহ, আমি প্রায় ভুলে গেছি। আমি আপনাকে যা দেখিয়েছি তার থেকে প্রক্সিগুলি অনেক বেশি ব্যবহৃত হয়। আপনি এখানে অন্যান্য ব্যবহার সম্পর্কে পড়তে পারেন ।"

সেতু প্যাটার্ন

প্যাটার্নস: অ্যাডাপ্টার, প্রক্সি, ব্রিজ - 2

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

"আমরা কি কেবল একটি নতুন বস্তু তৈরি করতে পারি না এবং এটি দিয়ে করা যায়?"

"সর্বদা নয়। ধরুন আপনার গাধাটি একগুচ্ছ অক্ষরের সাথে বন্ধু, অথবা সম্ভবত এটি বেশ কয়েকটি বানান দ্বারা প্রভাবিত ছিল, বা এটি নির্দিষ্ট অনুসন্ধানে জড়িত ছিল। অন্য কথায়, বস্তুটি ইতিমধ্যে অনেক জায়গায় ব্যবহার করা হতে পারে - এবং অন্যান্য অনেক বস্তুর সাথে লিঙ্ক করা হয়েছে। তাই এই ক্ষেত্রে, এটি একটি নতুন বস্তু তৈরি করার বিকল্প নয়।"

"আচ্ছা, তাহলে কি করা যায়?"

"ব্রিজ প্যাটার্ন সবচেয়ে সফল সমাধানগুলির মধ্যে একটি।"

"এই প্যাটার্নটি একটি বস্তুকে দুটি বস্তুতে বিভক্ত করে: একটি "ইন্টারফেস অবজেক্ট" এবং একটি "বাস্তবায়ন বস্তু"।"

"ইন্টারফেস এবং এটি প্রয়োগকারী ক্লাসের মধ্যে পার্থক্য কী?"

"একটি ইন্টারফেস এবং একটি ক্লাসের সাথে, আমরা একটি বস্তুর সাথে শেষ করি৷ কিন্তু এখানে — আমাদের দুটি আছে৷ এই উদাহরণটি দেখুন:"

উদাহরণ
class User
{
 private UserImpl realUser;

 public User(UserImpl impl)
 {
  realUser = impl;
 }

 public void run() //Run
 {
  realUser.run();
 }

 public void fly() //Fly
 {
  realUser.fly();
 }
}

class UserImpl
{
 public void run()
 {
 }

 public void fly()
 {
 }
}

"এবং তারপরে আপনি UserImpl-এর বিভিন্ন সাবক্লাস ঘোষণা করতে পারেন, উদাহরণস্বরূপ UserDonkey (গাধা) এবং UserDragon (ড্রাগন)।"

"একই, আমি সত্যিই বুঝতে পারছি না এটি কিভাবে কাজ করবে।"

"আচ্ছা, এরকম কিছু:"

উদাহরণ
class User
{
 private UserImpl realUser;

 public User(UserImpl impl)
 {
  realUser = impl;
 }

 public void transformToDonkey()
 {
  realUser = new UserDonkeyImpl();
 }

 public void transformToDragon()
 {
  realUser = new UserDragonImpl();
 }
}
কিভাবে এটা কাজ করে
User user = new User(new UserDonkey()); // Internally, we're a donkey
user.transformToDragon(); // Now we're a dragon internally

"সুতরাং এটি একটি প্রক্সির মত কিছু।"

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

"আহ। ধন্যবাদ। আপনি কি আমাকে এটি সম্পর্কে আরও পড়ার জন্য একটি লিঙ্ক দেবেন?"

"অবশ্যই, অ্যামিগো, আমার বন্ধু। এখানে আপনি যান: ব্রিজ প্যাটার্ন ।"