ওহে! আজ আমরা একটি গুরুত্বপূর্ণ নতুন বিষয়ে স্পর্শ করব: নকশার নিদর্শন । এই নিদর্শন কি? আমি মনে করি আপনি " চাকা পুনরায় উদ্ভাবন করবেন না " অভিব্যক্তিটি অবশ্যই জানেন । প্রোগ্রামিং-এ, অন্যান্য অনেক ক্ষেত্রের মতোই, প্রচুর সংখ্যক সাধারণ পরিস্থিতি রয়েছে। সফ্টওয়্যার বিকাশের সাথে সাথে তাদের প্রত্যেকের জন্য প্রস্তুত-তৈরি সমাধান তৈরি করা হয়েছে। এই সমাধানগুলিকে ডিজাইন প্যাটার্ন বলা হয়। নিয়ম অনুসারে, একটি প্যাটার্ন হল কিছু সমাধান যা এইভাবে তৈরি করা হয়: "যদি আপনার প্রোগ্রামে X করতে হয়, তাহলে এটি করার সেরা উপায়"। নিদর্শন প্রচুর আছে. চমৎকার বই "হেড ফার্স্ট ডিজাইন প্যাটার্নস", যা আপনার অবশ্যই পরিচিত হওয়া উচিত, তাদের জন্য উত্সর্গীকৃত।
সংক্ষেপে বললে, একটি প্যাটার্ন একটি সাধারণ সমস্যা এবং একটি সংশ্লিষ্ট সমাধান নিয়ে গঠিত যা এক ধরণের মান হিসাবে বিবেচিত হতে পারে। আজকের পাঠে, আমরা এই প্যাটার্নগুলির একটির সাথে দেখা করব: অ্যাডাপ্টার। এর নামই সব বলে, এবং আপনি বাস্তব জীবনে অনেকবার অ্যাডাপ্টারের সম্মুখীন হয়েছেন। কিছু সাধারণ অ্যাডাপ্টার হল কার্ড রিডার যা অনেক কম্পিউটার এবং ল্যাপটপে থাকে।
ধরুন আমাদের কিছু মেমরি কার্ড আছে। তো সমস্যাটা কী? এটি কম্পিউটারের সাথে কীভাবে যোগাযোগ করতে হয় তা জানে না। তারা একটি সাধারণ ইন্টারফেস ভাগ করে না। কম্পিউটারে একটি USB পোর্ট আছে, কিন্তু আমরা এতে মেমরি কার্ড ঢোকাতে পারি না। কার্ডটি কম্পিউটারে প্লাগ করা যায় না, তাই আমরা আমাদের ফটো, ভিডিও এবং অন্যান্য ডেটা সংরক্ষণ করতে পারি না। একটি কার্ড রিডার হল একটি অ্যাডাপ্টার যা এই সমস্যার সমাধান করে। সব পরে, এটি একটি USB তারের আছে! কার্ডের বিপরীতে, কার্ড রিডার কম্পিউটারে প্লাগ করা যেতে পারে। তারা কম্পিউটারের সাথে একটি সাধারণ ইন্টারফেস ভাগ করে: USB। চলুন দেখি এটি অনুশীলনে কেমন দেখায়:
পদ্ধতির একটি সেট একটি ইন্টারফেস কি অবিকল. আপনি দেখতে পাচ্ছেন, এই শ্রেণীর একটি আছে
যাইহোক,
এবং যদিও আমাদের


public interface USB {
void connectWithUsbCable();
}
এটি আমাদের ইউএসবি ইন্টারফেস যা ইউএসবি এর মাধ্যমে সংযোগ করার জন্য শুধুমাত্র একটি পদ্ধতি।
public class MemoryCard {
public void insert() {
System.out.println("Memory card successfully inserted!");
}
public void copyData() {
System.out.println("The data has been copied to the computer!");
}
}
এটি আমাদের ক্লাস যা মেমরি কার্ডের প্রতিনিধিত্ব করে। এটিতে ইতিমধ্যে আমাদের প্রয়োজনীয় 2টি পদ্ধতি রয়েছে, তবে এখানে সমস্যাটি রয়েছে: এটি USB ইন্টারফেস বাস্তবায়ন করে না। কার্ডটি USB পোর্টে ঢোকানো যাবে না।
public class CardReader implements USB {
private MemoryCard memoryCard;
public CardReader(MemoryCard memoryCard) {
this.memoryCard = memoryCard;
}
@Override
public void connectWithUsbCable() {
this.memoryCard.insert();
this.memoryCard.copyData();
}
}
এবং এখানে আমাদের অ্যাডাপ্টার! কি করেCardReader
ক্লাস করতে এবং ঠিক কি এটি একটি অ্যাডাপ্টার করে তোলে? এটা সব সহজ. যে ক্লাসটি অভিযোজিত হচ্ছে (মেমোরিকার্ড) সেটি অ্যাডাপ্টারের ক্ষেত্রগুলির মধ্যে একটি হয়ে ওঠে। এইবার বুঝতে পারছি. আমরা যখন বাস্তব জীবনে একটি কার্ড রিডারের ভিতরে একটি মেমরি কার্ড রাখি, তখন এটিও এর অংশ হয়ে যায়। মেমরি কার্ডের বিপরীতে, অ্যাডাপ্টারটি কম্পিউটারের সাথে একটি ইন্টারফেস ভাগ করে। এটিতে একটি USB কেবল রয়েছে, অর্থাৎ এটি USB এর মাধ্যমে অন্যান্য ডিভাইসের সাথে সংযুক্ত করা যেতে পারে। এজন্য আমাদের কার্ডরিডার ক্লাস USB ইন্টারফেস প্রয়োগ করে। কিন্তু এই পদ্ধতির ভিতরে ঠিক কী ঘটে? ঠিক কি আমাদের ঘটতে হবে! অ্যাডাপ্টার আমাদের মেমরি কার্ডে কাজ অর্পণ করে। প্রকৃতপক্ষে, অ্যাডাপ্টার নিজেই কিছু করে না। একটি কার্ড রিডারের কোনো স্বাধীন কার্যকারিতা নেই। এর কাজ শুধুমাত্র কম্পিউটার এবং মেমরি কার্ডের সাথে সংযোগ স্থাপন করা যাতে কার্ডটিকে তার কাজ করার অনুমতি দেওয়া হয় - ফাইলগুলি অনুলিপি করা!connectWithUsbCable()
পদ্ধতি) মেমরি কার্ডের "প্রয়োজন" মেটাতে। আসুন কিছু ক্লায়েন্ট প্রোগ্রাম তৈরি করি যা একজন ব্যক্তিকে অনুকরণ করবে যে মেমরি কার্ড থেকে ডেটা অনুলিপি করতে চায়:
public class Main {
public static void main(String[] args) {
USB cardReader = new CardReader(new MemoryCard());
cardReader.connectWithUsbCable();
}
}
তাহলে আমরা কি পেলাম? কনসোল আউটপুট:
Memory card successfully inserted!
The data has been copied to the computer!
চমৎকার। আমরা আমাদের লক্ষ্য অর্জন করেছি! অ্যাডাপ্টার প্যাটার্ন সম্পর্কে তথ্য সহ একটি ভিডিওর লিঙ্ক এখানে রয়েছে:
পাঠক এবং লেখক বিমূর্ত ক্লাস
এখন আমরা আমাদের প্রিয় ক্রিয়াকলাপে ফিরে যাব: ইনপুট এবং আউটপুট নিয়ে কাজ করার জন্য কয়েকটি নতুন ক্লাস সম্পর্কে শেখা :) আমি ভাবছি আমরা ইতিমধ্যে কতগুলি সম্পর্কে শিখেছি।Reader
আজ আমরা এবং ক্লাস সম্পর্কে কথা বলব Writer
. কেন বিশেষভাবে যারা ক্লাস? কারণ তারা অ্যাডাপ্টার সম্পর্কে আমাদের পূর্ববর্তী বিভাগের সাথে সম্পর্কিত। আসুন আরো বিস্তারিতভাবে তাদের পরীক্ষা করা যাক। আমরা দিয়ে শুরু করব Reader
। Reader
একটি বিমূর্ত শ্রেণী, তাই আমরা স্পষ্টভাবে বস্তু তৈরি করতে সক্ষম হব না। কিন্তু আপনি আসলে ইতিমধ্যেই এর সাথে পরিচিত! সর্বোপরি, আপনি BufferedReader
এবং InputStreamReader
শ্রেণীগুলির সাথে ভালভাবে পরিচিত, যা এর বংশধর :)
public class BufferedReader extends Reader {
…
}
public class InputStreamReader extends Reader {
…
}
ক্লাস InputStreamReader
একটি ক্লাসিক অ্যাডাপ্টার. আপনি সম্ভবত মনে রাখবেন, আমরা একটি InputStream
অবজেক্ট এর কনস্ট্রাক্টরের কাছে পাঠাতে পারি। এটি করার জন্য, আমরা সাধারণত System.in
ভেরিয়েবল ব্যবহার করি:
public static void main(String[] args) {
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
কিন্তু কি InputStreamReader
করে? প্রতিটি অ্যাডাপ্টারের মতো, এটি একটি ইন্টারফেসকে অন্যটিতে রূপান্তর করে। এই ক্ষেত্রে, InputStream
ইন্টারফেস ইন্টারফেস Reader
. প্রাথমিকভাবে, আমরা InputStream
ক্লাস আছে. এটি ভাল কাজ করে, কিন্তু আপনি শুধুমাত্র পৃথক বাইট পড়তে এটি ব্যবহার করতে পারেন। উপরন্তু, আমরা একটি Reader
বিমূর্ত ক্লাস আছে. এটির কিছু খুব দরকারী কার্যকারিতা রয়েছে — এটি অক্ষরগুলি কীভাবে পড়তে হয় তা জানে! আমাদের অবশ্যই এই ক্ষমতা প্রয়োজন। কিন্তু এখানে আমরা ক্লাসিক সমস্যাটির মুখোমুখি হই যা সাধারণত অ্যাডাপ্টার দ্বারা সমাধান করা হয় - অসঙ্গত ইন্টারফেস। ওটার মানে কি? আসুন ওরাকল ডকুমেন্টেশনটি একবার দেখে নেওয়া যাক। এখানে ক্লাসের পদ্ধতি আছে InputStream
। 
read()
পদ্ধতি (কয়েকটি রূপ, বাস্তবে), কিন্তু এটি শুধুমাত্র বাইট পড়তে পারে: হয় পৃথক বাইট, বা একটি বাফার ব্যবহার করে বেশ কয়েকটি বাইট। কিন্তু এই বিকল্পটি আমাদের জন্য উপযুক্ত নয় — আমরা অক্ষর পড়তে চাই। আমাদের এমন কার্যকারিতা দরকার যা ইতিমধ্যেই Reader
বিমূর্ত শ্রেণিতে প্রয়োগ করা হয়েছে । আমরা ডকুমেন্টেশনেও এটি দেখতে পারি। 
InputStream
এবং Reader
ইন্টারফেস বেমানান! আপনি দেখতে পাচ্ছেন, পদ্ধতির প্রতিটি বাস্তবায়নের read()
বিভিন্ন পরামিতি এবং রিটার্ন মান রয়েছে। এবং এই যেখানে আমাদের প্রয়োজন InputStreamReader
! এটা আমাদের ক্লাসের মধ্যে অ্যাডাপ্টার হিসেবে কাজ করবে ।কার্ড রিডারের উদাহরণের মতো, যা আমরা উপরে বিবেচনা করেছি, আমরা অ্যাডাপ্টার ক্লাসের "ভিতরে" শ্রেণীকে অভিযোজিত করার একটি উদাহরণ রাখি, অর্থাৎ আমরা তার কন্সট্রাক্টরের কাছে একটি পাস করি। আগের উদাহরণে, আমরা MemoryCard
ভিতরে একটি বস্তু রাখি CardReader
। InputStream
এখন আমরা কনস্ট্রাক্টরের কাছে একটি বস্তু প্রেরণ করছি InputStreamReader
! আমরা আমাদের পরিচিত System.in
ভেরিয়েবল ব্যবহার করি InputStream
:
public static void main(String[] args) {
InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
এবং প্রকৃতপক্ষে, ডকুমেন্টেশনের দিকে তাকিয়ে InputStreamReader
, আমরা দেখতে পারি যে অভিযোজন সফল হয়েছে :) এখন আমাদের হাতে অক্ষরগুলি পড়ার পদ্ধতি রয়েছে। 
System.in
অবজেক্ট (কীবোর্ডের সাথে আবদ্ধ স্ট্রীম) প্রাথমিকভাবে এটির অনুমতি দেয়নি, তবে ভাষার নির্মাতারা অ্যাডাপ্টার প্যাটার্ন প্রয়োগ করে এই সমস্যার সমাধান করেছেন। Reader
বেশিরভাগ I/O ক্লাসের মতো বিমূর্ত ক্লাসেরও একটি যমজ ভাই আছে — Writer
। এটির একই বড় সুবিধা রয়েছে Reader
- এটি অক্ষরের সাথে কাজ করার জন্য একটি সুবিধাজনক ইন্টারফেস প্রদান করে। আউটপুট স্ট্রীমগুলির সাথে, সমস্যা এবং এর সমাধান ইনপুট স্ট্রিমগুলির মতোই দেখায়৷ একটি ক্লাস আছে OutputStream
যে শুধুমাত্র বাইট লিখতে পারে, একটি আছেWriter
বিমূর্ত শ্রেণী যা অক্ষরের সাথে কাজ করতে জানে এবং দুটি বেমানান ইন্টারফেস রয়েছে। এই সমস্যাটি আবার অ্যাডাপ্টার প্যাটার্ন দ্বারা সমাধান করা হয়। আমরা ক্লাস এবং ক্লাসের OutputStreamWriter
দুটি ইন্টারফেস একে অপরের সাথে সহজেই মানিয়ে নিতে ক্লাস ব্যবহার করি। কনস্ট্রাক্টরের কাছে একটি বাইট স্ট্রীম পাস করার পরে , আমরা বাইটের পরিবর্তে অক্ষর লিখতে একটি ব্যবহার করতে পারি! Writer
OutputStream
OutputStream
OutputStreamWriter
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
OutputStreamWriter streamWriter = new OutputStreamWriter(new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt"));
streamWriter.write(32144);
streamWriter.close();
}
}
আমরা আমাদের ফাইলে কোড 32144 (綐) দিয়ে অক্ষরটি লিখেছি, বাইট দিয়ে কাজ করার প্রয়োজনীয়তা দূর করে :) আজকের জন্য এটাই। পরবর্তী পাঠে দেখা হবে! :)
GO TO FULL VERSION