Behavioral Design Patterns হলো সেই ধরনের ডিজাইন প্যাটার্ন যা অবজেক্ট এবং ক্লাসের মধ্যে যোগাযোগ এবং আচরণকে নিয়ন্ত্রণ করতে সাহায্য করে। এই প্যাটার্নগুলি সাধারণত অবজেক্টগুলির মধ্যে যোগাযোগের পদ্ধতি নির্ধারণ, কার্যকলাপের শ্রেণীবিভাগ, এবং অবজেক্টগুলির মধ্যে সংযোগের লজিক সাজানোর জন্য ব্যবহৃত হয়। Behavioral patterns মূলত ক্লাসের এবং অবজেক্টের একে অপরের সাথে কীভাবে সম্পর্কিত এবং যোগাযোগ করে তা নির্ধারণ করে।
এই গাইডে আমরা Behavioral Design Patterns এর মধ্যে কিছু জনপ্রিয় প্যাটার্ন যেমন Strategy, Observer, Command, Iterator, এবং State প্যাটার্নের আলোচনা করব।
1. Strategy Pattern
Strategy Pattern একটি অ্যালগরিদমের প্যাকেজ তৈরি করার এবং তাদের একে অপরের পরিবর্তে ব্যবহার করার পদ্ধতি। এই প্যাটার্নের সাহায্যে, একটি ক্লাসের মধ্যে বিভিন্ন অ্যালগরিদম রাখা হয় এবং প্রয়োজনমতো সেগুলি নির্বাচিত করা যায়। এটি ক্লাসের আচরণকে runtime এ পরিবর্তন করতে সাহায্য করে।
Strategy Pattern Example (Java)
// Strategy interface
interface PaymentStrategy {
void pay(int amount);
}
// Concrete Strategy classes
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " using Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " using PayPal");
}
}
// Context class
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}
// Client code
public class StrategyPatternExample {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100);
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(200);
}
}
Explanation:
- Strategy interface: এটি বিভিন্ন পেমেন্ট মেথডের জন্য একটি সাধারণ ইন্টারফেস।
- Concrete strategies: এগুলি হল বাস্তবায়ন, যেখানে পেমেন্ট পদ্ধতির প্রতিটি বিশেষ রূপ নির্দিষ্ট করা হয়।
- Context class: এখানে ShoppingCart ক্লাসটি পেমেন্ট স্ট্রাটেজি সেট করে এবং ব্যবহারকারীর চাহিদা অনুযায়ী পেমেন্ট প্রক্রিয়া পরিচালনা করে।
2. Observer Pattern
Observer Pattern একটি একে অপরের সাথে সংযুক্ত অবজেক্টের মধ্যে একাধিক অবজেক্টে অবস্থা পরিবর্তন জানানো হয়। এটি একাধিক শ্রোতা (observers) থাকতে পারে যারা মূল বিষয় (subject) থেকে তাদের আপডেট পেতে চান। যখন মূল বিষয়টি পরিবর্তিত হয়, তখন সমস্ত অবজেক্টকে অবহিত করা হয়।
Observer Pattern Example (Java)
import java.util.ArrayList;
import java.util.List;
// Subject class
class Subject {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
// Observer interface
interface Observer {
void update(String message);
}
// Concrete Observer classes
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println(name + " received: " + message);
}
}
// Client code
public class ObserverPatternExample {
public static void main(String[] args) {
Subject subject = new Subject();
Observer observer1 = new ConcreteObserver("Observer1");
Observer observer2 = new ConcreteObserver("Observer2");
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers("New Update Available!");
}
}
Explanation:
- Subject class: এই ক্লাসে addObserver, removeObserver, এবং notifyObservers মেথডগুলি রয়েছে যা অবজারভারগুলিকে নিবন্ধন করে এবং তাদের আপডেট জানায়।
- Observer interface: একটি সাধারণ ইন্টারফেস যা সমস্ত অবজারভারদের জন্য আপডেট মেথড সরবরাহ করে।
- Concrete Observer classes: অবজারভার ক্লাস যেগুলি প্রকৃতভাবে সিস্টেমে পরিবর্তনগুলি গ্রহণ করে এবং সেগুলি প্রক্রিয়া করে।
3. Command Pattern
Command Pattern একটি আচরণগত প্যাটার্ন যা encapsulates a request বা অপারেশনকে একটি অবজেক্টের মধ্যে, যাতে সেই অনুরোধটি পরবর্তীতে বিভিন্নভাবে প্রক্রিয়া করা বা পরিচালনা করা যেতে পারে। এটি সাধারণত undo বা redo অপারেশনগুলো করতে ব্যবহৃত হয়।
Command Pattern Example (Java)
// Command interface
interface Command {
void execute();
}
// Concrete Command classes
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
}
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
}
// Receiver class
class Light {
public void turnOn() {
System.out.println("Light is ON");
}
public void turnOff() {
System.out.println("Light is OFF");
}
}
// Invoker class
class RemoteControl {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void pressButton() {
command.execute();
}
}
// Client code
public class CommandPatternExample {
public static void main(String[] args) {
Light light = new Light();
Command lightOn = new LightOnCommand(light);
Command lightOff = new LightOffCommand(light);
RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton();
remote.setCommand(lightOff);
remote.pressButton();
}
}
Explanation:
- Command interface: এটি execute() মেথড প্রদান করে, যা প্রতিটি কমান্ড ক্লাসের মধ্যে সম্পাদিত হয়।
- Concrete Command classes: প্রতিটি কমান্ড ক্লাস যেটি একটি নির্দিষ্ট অ্যাকশন (যেমন turnOn বা turnOff) সম্পাদন করে।
- Receiver class: যেখানে আসল কাজ বা অপারেশনটি সম্পাদিত হয় (এখানে Light ক্লাস)।
- Invoker class: এটি command মেথডটি কল করে এবং সেই অনুরোধটি সম্পাদন করে (এখানে RemoteControl ক্লাস)।
4. Iterator Pattern
Iterator Pattern একটি অবজেক্টের উপাদানগুলির উপর ইটারেটর তৈরি করে, যাতে উপাদানগুলির মধ্যে দিয়ে চলা এবং পরবর্তী উপাদানগুলির কাছে পৌঁছানো সহজ হয়। এটি অবজেক্টের ইন্টারফেসের বাইরে বাইরে থেকে কোনো তথ্য পরিবর্তন না করে sequential access প্রদান করে।
Iterator Pattern Example (Java)
import java.util.ArrayList;
import java.util.List;
// Iterable class
class NameRepository implements Iterable<String> {
private List<String> names = new ArrayList<>();
public NameRepository() {
names.add("John");
names.add("Jane");
names.add("Jack");
}
@Override
public java.util.Iterator<String> iterator() {
return new NameIterator(names);
}
}
// Iterator class
class NameIterator implements java.util.Iterator<String> {
private List<String> names;
private int position;
public NameIterator(List<String> names) {
this.names = names;
this.position = 0;
}
@Override
public boolean hasNext() {
return position < names.size();
}
@Override
public String next() {
return hasNext() ? names.get(position++) : null;
}
}
// Client code
public class IteratorPatternExample {
public static void main(String[] args) {
NameRepository nameRepository = new NameRepository();
for (String name : nameRepository) {
System.out.println("Name: " + name);
}
}
}
Explanation:
- Iterator interface: এটি hasNext() এবং next() মেথড প্রদান করে যা ডাটা খোঁজার জন্য ব্যবহৃত হয়।
- Iterable class: এটি একটি কন্টেইনার ক্লাস যা উপাদানগুলির উপর iterator তৈরি করে।
- Iterator class: এটি উপাদানগুলির মধ্যে দিয়ে যাওয়া এবং প্রতিটি উপাদান একে একে ফেরত দেয়।
5. State Pattern
State Pattern একটি অবজেক্টের অবস্থা পরিবর্তন করার পদ্ধতি নিশ্চিত করে, যেখানে অবস্থা পরিবর্তন হলে সেই অবস্থা অনুযায়ী আচরণও পরিবর্তিত হয়। এটি state-specific behavior তৈরি করে যা অবজেক্টের চলমান অবস্থার উপর নির্ভর করে।
State Pattern Example (Java)
// State interface
interface State {
void doAction(Context context);
}
// Concrete States
class StartState implements State {
@Override
public void doAction(Context context) {
System.out.println("Player is in Start State");
context.setState(this);
}
}
class StopState implements State {
@Override
public void doAction(Context context) {
System.out.println("Player is in Stop State");
context.setState(this);
}
}
// Context class
class Context {
private State state;
public Context() {
state = null;
}
public void setState(State state) {
this.state = state;
}
public State getState() {
return state;
}
}
// Client code
public class StatePatternExample {
public static void main(String[] args) {
Context context = new Context();
StartState startState = new StartState();
startState.doAction(context);
System.out.println(context.getState().getClass().getName());
StopState stopState = new StopState();
stopState.doAction(context);
System.out.println(context.getState().getClass().getName());
}
}
Explanation:
- State interface: একটি সাধারণ ইন্টারফেস যা সমস্ত রাষ্ট্রের আচরণ সংজ্ঞায়িত করে।
- Concrete States: বাস্তবায়ন যা অবস্থা অনুযায়ী কার্যকরী হবে।
- Context class: এটি একটি অবজেক্টের অবস্থা ধারণ করে এবং সেই অবস্থা পরিবর্তনের জন্য ব্যবহৃত হয়।
সারাংশ
Behavioral Design Patterns অবজেক্ট এবং ক্লাসগুলির মধ্যে পারস্পরিক সম্পর্ক এবং আচরণ ব্যবস্থাপনার জন্য অত্যন্ত গুরুত্বপূর্ণ। আমরা আলোচনা করেছি কিছু জনপ্রিয় Behavioral Design Patterns:
- Strategy Pattern: অ্যালগরিদমের প্যাকেজ তৈরি এবং পরিবর্তনযোগ্যতা।
- Observer Pattern: একাধিক অবজেক্টকে মূল অবজেক্টের অবস্থা জানানো।
- Command Pattern: একটি অপারেশনকে একটি অবজেক্টে ইনক্যাপসুলেট করা।
- Iterator Pattern: একটি অবজেক্টের উপাদানগুলির উপর ইটারেশন করা।
- State Pattern: অবস্থা পরিবর্তনের মাধ্যমে অবজেক্টের আচরণ পরিবর্তন করা।
এই প্যাটার্নগুলি সিস্টেমের আচরণকে সহজ, আরও স্থিতিশীল এবং বহনযোগ্য করতে সহায়ক।
Chain of Responsibility Pattern একটি Behavioral Design Pattern যা একটি প্রক্রিয়া বা কনসেপ্টের মাধ্যমে অনুরোধ গুলির পরিচালনা করতে ব্যবহৃত হয়। এই প্যাটার্নে, একটি চেইন (দ্বারা একাধিক অবজেক্টের মাধ্যমে) বার্তা বা অনুরোধের প্রক্রিয়া স্থানান্তরিত করা হয়, যাতে একাধিক অবজেক্ট এটি প্রক্রিয়া করতে পারে।
এই প্যাটার্নের মূল লক্ষ্য হলো, অনুরোধটি কোন অবজেক্টের মাধ্যমে প্রক্রিয়া হবে তা আগে থেকেই নির্ধারণ না করে, একটি চেইন তৈরি করা, যেখানে প্রতিটি অবজেক্ট নিজের দায়িত্ব অনুযায়ী অনুরোধটি প্রক্রিয়া করতে সক্ষম। যদি একটি অবজেক্ট অনুরোধটি প্রক্রিয়া না করতে পারে, তবে এটি পরবর্তী অবজেক্টে পাঠানো হয় এবং এই প্রক্রিয়া চেইন আকারে চলতে থাকে।
Chain of Responsibility Pattern এর বৈশিষ্ট্যসমূহ:
- Responsibility Distribution: একাধিক অবজেক্টের মধ্যে একটি কাজের দায়বদ্ধতা ভাগ করা হয়।
- Loosely Coupled: এটি অবজেক্টগুলির মধ্যে জোরালো সম্পর্ক সৃষ্টি না করে, তাদের মধ্যে আলাদা আলাদা দায়িত্ব ভাগ করে দেয়।
- Flexible: নতুন অবজেক্ট বা হ্যান্ডলার অ্যাড করার জন্য সহজ।
Chain of Responsibility Pattern এর কাঠামো:
- Handler: এটি একটি ইন্টারফেস বা অ্যাবস্ট্রাক্ট ক্লাস হতে পারে, যার মধ্যে একটি request handling করার জন্য একটি
handleRequest()মেথড থাকে। - ConcreteHandler: এটি
Handlerক্লাস বা ইন্টারফেসের একটি কনক্রিট ইমপ্লিমেন্টেশন। এই ক্লাসে অনুরোধ প্রক্রিয়া করার লজিক থাকে এবং পরবর্তী অবজেক্টে (হ্যান্ডলার) অনুরোধটি পাঠানোর জন্য একটি রেফারেন্স থাকে। - Client: ক্লায়েন্ট অনুরোধ পাঠায় এবং চেইন অফ হ্যান্ডলার গুলি সেগুলি প্রক্রিয়া করে।
Chain of Responsibility Pattern উদাহরণ (Java)
ধরা যাক, আমাদের একটি সিস্টেম তৈরি করতে হবে যেখানে এজেন্ট এবং ম্যানেজার একটি কমপ্লেন-এ কাজ করবে, কিন্তু তাদের মধ্যে দায়িত্ব ভাগ করা থাকবে। ক্লায়েন্ট যদি প্রথমে এজেন্টকে কমপ্লেনটি দেন, তবে এজেন্ট যদি কমপ্লেনটি সমাধান করতে না পারে, তবে সেটি ম্যানেজার এর কাছে চলে যাবে।
Step 1: Handler Interface
interface ComplaintHandler {
void handleComplaint(String complaint);
}
Step 2: ConcreteHandler Classes
class Agent implements ComplaintHandler {
private ComplaintHandler nextHandler;
@Override
public void handleComplaint(String complaint) {
if (complaint.equalsIgnoreCase("Minor issue")) {
System.out.println("Agent is handling the complaint: " + complaint);
} else {
if (nextHandler != null) {
nextHandler.handleComplaint(complaint);
}
}
}
public void setNextHandler(ComplaintHandler nextHandler) {
this.nextHandler = nextHandler;
}
}
class Manager implements ComplaintHandler {
@Override
public void handleComplaint(String complaint) {
System.out.println("Manager is handling the complaint: " + complaint);
}
}
Step 3: Client Code
public class ChainOfResponsibilityExample {
public static void main(String[] args) {
// Create handlers
ComplaintHandler agent = new Agent();
ComplaintHandler manager = new Manager();
// Set next handler for agent
((Agent) agent).setNextHandler(manager);
// Client submitting complaints
agent.handleComplaint("Minor issue"); // Handled by agent
agent.handleComplaint("Major issue"); // Handled by manager
}
}
ব্যাখ্যা:
- ComplaintHandler: এটি একটি ইন্টারফেস যা
handleComplaint()মেথড নির্ধারণ করে। - Agent: এটি একটি কনক্রিট হ্যান্ডলার যা প্রথমে অভিযোগ দেখে যদি সেটা তার সীমানার মধ্যে থাকে তবে সেটি সমাধান করে। যদি না পারে, তবে
nextHandlerএর কাছে পাঠানো হয়। - Manager: এটি একটি দ্বিতীয় কনক্রিট হ্যান্ডলার যা পরে চলতে থাকে, যদি প্রথম হ্যান্ডলার (এজেন্ট) সমাধান না করে।
- Client Code: ক্লায়েন্ট প্রথমে এজেন্ট এর কাছে অভিযোগ পাঠায় এবং যদি সেটি সমাধান না হয়, তবে তা ম্যানেজার এর কাছে চলে যায়।
আউটপুট:
Agent is handling the complaint: Minor issue
Manager is handling the complaint: Major issue
Chain of Responsibility Pattern এর সুবিধা এবং ব্যবহার
সুবিধা:
- লোস লিংকড: এটি অবজেক্টগুলির মধ্যে খুব কম সম্পর্ক তৈরি করে, যার ফলে নতুন হ্যান্ডলার যোগ করা সহজ হয়ে যায়।
- ডায়নামিক নিয়ন্ত্রণ: এটি বিভিন্ন ধরণের সমস্যার জন্য একাধিক হ্যান্ডলার ব্যবহার করতে দেয়।
- কোডে স্পষ্টতা বৃদ্ধি: প্রতিটি হ্যান্ডলার এককভাবে কাজ করার কারণে কোডের অর্গানাইজেশন পরিষ্কার হয়।
ব্যবহার:
- ইভেন্ট হ্যান্ডলিং: ইভেন্ট বা ইনপুট প্রক্রিয়াতে যেখানে একাধিক সাব-প্রসেস তাদের নিজ নিজ দায়িত্বে কাজ করে।
- লগিং ফ্রেমওয়ার্ক: একটি লগিং সিস্টেম যেখানে একাধিক লগ হ্যান্ডলার থাকে (যেমন, FileHandler, ConsoleHandler, DatabaseHandler)।
- এজেন্ট-ম্যানেজার সিস্টেম: যেখানে কমপ্লেনের বা সমস্যার জন্য একাধিক স্তর (Agent, Manager, Director) থাকে।
সারাংশ
Chain of Responsibility Pattern হল একটি বিহেভিয়ারাল ডিজাইন প্যাটার্ন যা একটি চেইন তৈরি করে যাতে একাধিক অবজেক্ট বা হ্যান্ডলার অনুসন্ধান বা প্রক্রিয়াজাতকরণের দায়িত্ব নেয়। এটি কোডের মধ্যকার জটিলতা কমায় এবং বিভিন্ন প্রক্রিয়া বা অনুসন্ধান অবজেক্টের মধ্যে দায়িত্ব ভাগ করে দেয়, যাতে প্রতিটি অবজেক্ট একে অপরের সাথে সম্পর্কিত না হয়ে কাজ করতে পারে। Java তে এই প্যাটার্নটি ব্যবহারে কোডের পুনঃব্যবহারযোগ্যতা, এবং রক্ষণাবেক্ষণযোগ্যতা বাড়ানো যায়, এবং সিস্টেমকে আরো ফ্লেক্সিবল ও এডজাস্টেবল করা যায়।
Command Pattern হল একটি Behavioral Design Pattern, যা একটি অবজেক্টে একটি অনুরোধ (request) বা কমান্ড (command) encapsulate করে এবং পরে সেই কমান্ডগুলো একে একে execute করার সুযোগ দেয়। এটি নির্দেশ করে, কমান্ডের সৃষ্টিকর্তা এবং তার কার্যকরী অংশগুলির মধ্যে একটি মধ্যস্থতাকারী স্তর তৈরি করা হয়। Command Pattern ব্যবহার করে, ব্যবহারকারীরা সহজেই কমান্ডগুলো সঞ্চালন করতে পারে এবং কমান্ডগুলির কার্যকারিতা পুরো সিস্টেমে বিচ্ছিন্নভাবে কাজ করে।
এই প্যাটার্নে কমান্ডের সৃষ্টিকর্তা, এক্সিকিউটর, এবং ব্যবহারকারী সবই আলাদা হয়, যার ফলে কোডকে নমনীয় ও সঠিকভাবে রক্ষণাবেক্ষণযোগ্য করা যায়। এতে অনেক সুবিধা রয়েছে, যেমন:
- Undo/Redo Operation: এটি Undo বা Redo এর জন্য ব্যবহৃত হতে পারে, কারণ প্রতিটি কমান্ড একটি অবজেক্ট হিসেবে থাকে এবং তার ইতিহাস ট্র্যাক করা সহজ।
- Queueing of requests: এটি কমান্ডগুলিকে একটি কিউতে রেখে একে একে এক্সিকিউট করার জন্য ব্যবহৃত হতে পারে।
Command Pattern এর গঠন
Command Pattern মূলত ৩টি অংশে বিভক্ত:
- Command Interface: এটি একটি সাধারণ ইন্টারফেস যা সকল কমান্ড ক্লাসের জন্য থাকে, এবং সাধারণত execute() মেথড থাকে।
- Concrete Command: এটি Command ইন্টারফেস ইমপ্লিমেন্ট করে এবং নির্দিষ্ট Receiver (যেমন একটি অবজেক্ট) এর মাধ্যমে execute() মেথডে আদেশ সম্পাদন করে।
- Invoker: এটি সেই অবজেক্ট যা কমান্ডগুলিকে কল করে। এটি কমান্ডের একটি রেফারেন্স ধারণ করে এবং সেই কমান্ডটি কার্যকর করে।
- Receiver: এটি কমান্ডের কার্যকারিতা (যেমন কোনো অপারেশন) সম্পাদন করে।
Command Pattern এর উদাহরণ
ধরা যাক, আমাদের একটি Home Automation System রয়েছে, যেখানে বিভিন্ন কমান্ড আছে, যেমন Turn On Light, Turn Off Light, Turn On Fan, ইত্যাদি। এই কমান্ডগুলোকে একটি Invoker এর মাধ্যমে চালানো হবে এবং প্রতিটি কমান্ড Receiver কে ব্যবহার করে কার্যকর হবে।
Step-by-step উদাহরণ:
1. Command Interface:
// Command Interface
interface Command {
void execute();
}
2. Concrete Command Classes:
// Concrete Command: TurnOnLightCommand
class TurnOnLightCommand implements Command {
private Light light;
public TurnOnLightCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOn();
}
}
// Concrete Command: TurnOffLightCommand
class TurnOffLightCommand implements Command {
private Light light;
public TurnOffLightCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.turnOff();
}
}
// Concrete Command: TurnOnFanCommand
class TurnOnFanCommand implements Command {
private Fan fan;
public TurnOnFanCommand(Fan fan) {
this.fan = fan;
}
@Override
public void execute() {
fan.turnOn();
}
}
// Concrete Command: TurnOffFanCommand
class TurnOffFanCommand implements Command {
private Fan fan;
public TurnOffFanCommand(Fan fan) {
this.fan = fan;
}
@Override
public void execute() {
fan.turnOff();
}
}
3. Receiver Classes:
// Receiver Class: Light
class Light {
public void turnOn() {
System.out.println("Light is ON");
}
public void turnOff() {
System.out.println("Light is OFF");
}
}
// Receiver Class: Fan
class Fan {
public void turnOn() {
System.out.println("Fan is ON");
}
public void turnOff() {
System.out.println("Fan is OFF");
}
}
4. Invoker Class:
// Invoker Class: RemoteControl
class RemoteControl {
private Command command;
// Set the command dynamically
public void setCommand(Command command) {
this.command = command;
}
// Invoke the command
public void pressButton() {
command.execute();
}
}
5. Client Code (Testing the Command Pattern):
public class CommandPatternDemo {
public static void main(String[] args) {
// Create receivers
Light light = new Light();
Fan fan = new Fan();
// Create concrete command objects
Command turnOnLight = new TurnOnLightCommand(light);
Command turnOffLight = new TurnOffLightCommand(light);
Command turnOnFan = new TurnOnFanCommand(fan);
Command turnOffFan = new TurnOffFanCommand(fan);
// Create invoker
RemoteControl remote = new RemoteControl();
// Simulate button presses
remote.setCommand(turnOnLight);
remote.pressButton();
remote.setCommand(turnOffLight);
remote.pressButton();
remote.setCommand(turnOnFan);
remote.pressButton();
remote.setCommand(turnOffFan);
remote.pressButton();
}
}
Output:
Light is ON
Light is OFF
Fan is ON
Fan is OFF
Command Pattern এর সুবিধা:
- Separation of Concerns: Command Pattern রিসিভার (যেমন
Light,Fan) এবং ইনভোকারের (যেমনRemoteControl) মধ্যে সম্পর্ককে আলাদা করে, ফলে সিস্টেমের পরিবর্তন এবং রক্ষণাবেক্ষণ সহজ হয়। - Undo/Redo functionality: Command Pattern সহজেই Undo বা Redo অপারেশন বাস্তবায়ন করতে সাহায্য করে, কারণ প্রত্যেকটি কমান্ড একটি অবজেক্টের মধ্যে থাকে।
- Queueing of requests: এটি কুয়েরি বা কমান্ডগুলোকে একটি কিউতে রাখা এবং তাদের পরবর্তীতে একে একে এক্সিকিউট করতে ব্যবহার করা যেতে পারে।
Command Pattern এর সীমাবদ্ধতা:
- Complexity: অনেক সময় এই প্যাটার্নটি ছোট প্রজেক্টে ব্যবহার করা হলে অতিরিক্ত জটিলতা তৈরি করতে পারে, কারণ এতে অনেক ক্লাস তৈরি হয়।
- Overhead: একাধিক কমান্ড এবং রিসিভার তৈরি করতে হলে অতিরিক্ত রিসোর্স প্রয়োজন হতে পারে।
সারাংশ
Command Pattern একটি শক্তিশালী ডিজাইন প্যাটার্ন যা কমান্ডগুলিকে একটি অবজেক্টে encapsulate করে, এবং পরে সেগুলিকে execute করার সুযোগ দেয়। এটি ব্যবহৃত হয় সফটওয়্যার সিস্টেমে যেখানে ক্লায়েন্টদের থেকে কমান্ড রিসিভ করে পরে সেগুলিকে কার্যকর করা হয়। Command Pattern সহজেই Undo/Redo, Queueing of Requests, এবং Job Scheduling এর জন্য ব্যবহার করা যায়, যা সফটওয়্যার সিস্টেমকে নমনীয় এবং সঠিকভাবে রক্ষণাবেক্ষণযোগ্য করে তোলে।
Interpreter Pattern একটি Behavioral Design Pattern যা সাধারণত ভাষা বা ভাষার সিনট্যাক্স বিশ্লেষণ করতে ব্যবহৃত হয়। এটি এমন ধরনের প্যাটার্ন যা একটি গ্রামার বা সিনট্যাক্স বিশ্লেষণ করতে সাহায্য করে, এবং একই ধরনের সমস্যা সমাধানে বিভিন্ন রুলস বা এক্সপ্রেশন ব্যবহার করে। Interpreter Pattern এর মূল উদ্দেশ্য হল একটি ভাষার জন্য ইন্টারপ্রেটার বা পার্সার তৈরি করা।
Interpreter Pattern এর উদ্দেশ্য:
- এটি একটি রুল বা এক্সপ্রেশন ভিত্তিক ডিজাইন প্যাটার্ন যা একটি ভাষা (যেমন গাণিতিক এক্সপ্রেশন বা সিনট্যাক্স) ব্যাখ্যা করতে সাহায্য করে।
- এটি সাধারণত এনএফএফএ (Expression Grammar) এবং অন্যান্য ভাষার ব্যবহৃত নিয়মগুলোকে কষ্টকর কাজের জন্য সহজে পরিণত করে।
Core Components of Interpreter Pattern:
- Abstract Expression: এটি একটি সাধারণ ইন্টারফেস প্রদান করে যা প্রতিটি এক্সপ্রেশন ক্লাস দ্বারা ইমপ্লিমেন্ট করা হয়।
- Terminal Expression: এটি একক এক্সপ্রেশন বা লেটার সিম্বল এবং গ্রামারের গুরুত্বপূর্ণ নিয়ম।
- Non-terminal Expression: এটি একাধিক এক্সপ্রেশন বা শাখার জন্য ব্যবহৃত হয় এবং এটি
AbstractExpressionকে ব্যবহার করে একটি কাঠামো তৈরি করে। - Context: এক্সপ্রেশনগুলির প্রক্রিয়াকরণের জন্য প্রয়োজনীয় ডেটা ধারণ করে।
Interpreter Pattern এর উদাহরণ: গাণিতিক এক্সপ্রেশন
ধরা যাক, আমাদের একটি গাণিতিক এক্সপ্রেশন যেমন 2 + 3 বা 5 * 3 + 2 ইন্টারপ্রেট করতে হবে। এই এক্সপ্রেশনগুলি ইন্টারপ্রেট করার জন্য Interpreter Pattern ব্যবহৃত হতে পারে। এখানে, আমরা একটি খুব সাধারণ ক্যালকুলেটর তৈরি করব যা +, -, *, / অপারেশন পরিচালনা করবে।
১. Abstract Expression Interface
interface Expression {
int interpret();
}
২. Terminal Expressions (সংখ্যা বা অপারেটর)
class Number implements Expression {
private int number;
public Number(int number) {
this.number = number;
}
@Override
public int interpret() {
return number;
}
}
class Add implements Expression {
private Expression leftExpression;
private Expression rightExpression;
public Add(Expression left, Expression right) {
this.leftExpression = left;
this.rightExpression = right;
}
@Override
public int interpret() {
return leftExpression.interpret() + rightExpression.interpret();
}
}
class Subtract implements Expression {
private Expression leftExpression;
private Expression rightExpression;
public Subtract(Expression left, Expression right) {
this.leftExpression = left;
this.rightExpression = right;
}
@Override
public int interpret() {
return leftExpression.interpret() - rightExpression.interpret();
}
}
class Multiply implements Expression {
private Expression leftExpression;
private Expression rightExpression;
public Multiply(Expression left, Expression right) {
this.leftExpression = left;
this.rightExpression = right;
}
@Override
public int interpret() {
return leftExpression.interpret() * rightExpression.interpret();
}
}
class Divide implements Expression {
private Expression leftExpression;
private Expression rightExpression;
public Divide(Expression left, Expression right) {
this.leftExpression = left;
this.rightExpression = right;
}
@Override
public int interpret() {
return leftExpression.interpret() / rightExpression.interpret();
}
}
৩. Client Code (এন্টারপ্রেটার ব্যবহার করা)
public class InterpreterPatternTest {
public static void main(String[] args) {
// 5 + 3 - 2 * 10
Expression five = new Number(5);
Expression three = new Number(3);
Expression two = new Number(2);
Expression ten = new Number(10);
Expression add = new Add(five, three);
Expression multiply = new Multiply(two, ten);
Expression subtract = new Subtract(add, multiply);
System.out.println("Result: " + subtract.interpret()); // Output will be 5 + 3 - (2 * 10)
}
}
ব্যাখ্যা:
- Number ক্লাসটি একক সংখ্যা ধারণ করে এবং তার মান রিটার্ন করে।
- Add, Subtract, Multiply, এবং Divide ক্লাসগুলি Expression ইন্টারফেস ইমপ্লিমেন্ট করে, এবং তারা তাদের মধ্যে থাকা এক্সপ্রেশনগুলি থেকে ফলাফল বের করার জন্য তাদের ইন্টারপ্রেট মেথড ব্যবহার করে।
- InterpreterPatternTest ক্লাসে, আমরা
5 + 3 - (2 * 10)এই এক্সপ্রেশনটি তৈরি করেছি এবং তার ফলাফল প্রিন্ট করেছি।
আউটপুট:
Result: -9
এখানে, প্রথমে 5 + 3 = 8, তারপর 2 * 10 = 20, এবং পরে 8 - 20 = -9।
Interpreter Pattern এর সুবিধা:
- Simplicity in Expression Parsing:
- এক্সপ্রেশন পার্সিং বা ব্যাখ্যার জন্য খুবই সহজ এবং সহজে সম্প্রসারণযোগ্য।
- Easy to Maintain:
- নতুন এক্সপ্রেশন বা রুলস যোগ করা সহজ এবং পূর্ববর্তী কোডের সাথে সামঞ্জস্যপূর্ণ থাকে।
- Reusability:
- এক্সপ্রেশন এবং তাদের পার্সিং কোড পুনরায় ব্যবহার করা যায়, একাধিক প্রজেক্টে এটি কাজে আসতে পারে।
সারাংশ
Interpreter Pattern হলো একটি Behavioral Design Pattern যা বিভিন্ন ধরণের এক্সপ্রেশন (যেমন গাণিতিক, শর্তমূলক, বা ভাষাগত) ব্যাখ্যা বা পার্স করার জন্য ব্যবহৃত হয়। এটি মূলত Language Parsing বা Expression Evaluation এর জন্য ব্যবহৃত হয়। এই প্যাটার্নের মাধ্যমে, আপনি নতুন এক্সপ্রেশন রুল বা সিনট্যাক্স দ্রুত এবং কার্যকরীভাবে সংযোজন করতে পারেন এবং তাদের ব্যাখ্যা বা মূল্য নির্ধারণ করতে পারেন।
Key Takeaways:
- Interpreter Pattern জাভা প্রোগ্রামিং এ এক্সপ্রেশন বা ভাষা বিশ্লেষণের জন্য ব্যবহৃত হয়।
- এটি সাধারণত Syntax Parsing, Expression Evaluation, DSL (Domain-Specific Languages) ইত্যাদি ক্ষেত্রে ব্যবহৃত হয়।
- নতুন এক্সপ্রেশন রুলস যোগ করতে খুবই সুবিধাজনক এবং সিস্টেমের রক্ষণাবেক্ষণ সহজতর হয়।
Iterator Pattern হল একটি Behavioral Design Pattern, যা একটি নির্দিষ্ট ডেটা স্ট্রাকচারে থাকা উপাদানগুলির ওপর পুনরাবৃত্তি করার জন্য একটি একক ইন্টারফেস প্রদান করে। এই প্যাটার্নটি বিভিন্ন ধরনের ডেটা স্ট্রাকচারের মধ্যে কমন ইন্টারফেসের মাধ্যমে উপাদান অ্যাক্সেসের সুবিধা দেয়। এতে, একটি ডেটা স্ট্রাকচারের মধ্যে উপাদান ভ্রমণ করার জন্য বাইরের ক্লাস বা কোডের কোনও কিছু পরিবর্তন না করে পুনরাবৃত্তি করার পদ্ধতি প্রদান করা হয়।
Iterator Pattern এর উদ্দেশ্য:
- Encapsulation: Iterator Pattern ডেটা স্ট্রাকচার এবং তার ইন্টারফেসের ভিতরের বাস্তবায়নকে অ্যাক্সেসের বাইরে আবদ্ধ করে রাখে। এর মাধ্যমে, ক্লাসের মধ্যে ডেটা উপাদান পরিচালনার জন্য অন্য কোন কোড সরাসরি ডেটা স্ট্রাকচারের মধ্যে প্রবেশ করে না।
- Separation of Concerns: ডেটা স্ট্রাকচারের ইমপ্লিমেন্টেশন এবং উপাদান পুনরাবৃত্তি করার লজিককে পৃথক করে।
- Simplification: আপনি যে ডেটা স্ট্রাকচারের ওপর কাজ করছেন সেটির ভেতরের কাঠামো সম্পর্কে জানার প্রয়োজন ছাড়াই উপাদানগুলোতে ভ্রমণ করতে পারেন।
Iterator Pattern এর মৌলিক উপাদান:
- Iterator Interface: এটি একটি ইন্টারফেস যা
hasNext()এবংnext()মেথড ডিফাইন করে, যাতে উপাদানগুলোর উপর পুনরাবৃত্তি করা যায়। - Concrete Iterator: এটি
Iteratorইন্টারফেসের বাস্তবায়ন এবং ডেটা স্ট্রাকচার (যেমন অ্যারে, লিঙ্কড লিস্ট, স্ট্যাক ইত্যাদি) এর উপর পুনরাবৃত্তি করার জন্য প্রয়োজনীয় ফাংশনালিটি প্রদান করে। - Aggregate (Collection): এটি যে ডেটা স্ট্রাকচার বা সংগ্রহের উপাদানগুলোর ওপর পুনরাবৃত্তি করা হচ্ছে তার প্রতিনিধিত্ব করে। এটি সাধারণত
createIterator()মেথড প্রদান করে যাIteratorঅবজেক্ট তৈরি করে।
উদাহরণ: Iterator Pattern in Java
ধরা যাক, আমাদের একটি Book Collection তৈরি করতে হবে, এবং আমরা বইগুলোর মধ্যে ইটারেটরের মাধ্যমে ভ্রমণ করতে চাই।
Step-by-Step Implementation:
- Iterator Interface: উপাদানগুলোর উপর পুনরাবৃত্তি করার জন্য দুটি প্রধান মেথড ডিফাইন করি —
hasNext()এবংnext()। - Concrete Iterator: আমাদের
BookIteratorক্লাস বাস্তবায়িত হবে যাIteratorইন্টারফেসের মেথডগুলোকে কার্যকর করবে। - Collection Interface: আমাদের BookCollection ক্লাস হবে যেখানে বইয়ের তালিকা থাকবে এবং এটি
createIterator()মেথড প্রদান করবে।
// Iterator Interface
interface Iterator {
boolean hasNext();
Object next();
}
// Concrete Iterator
class BookIterator implements Iterator {
private Book[] books;
private int index;
public BookIterator(Book[] books) {
this.books = books;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < books.length && books[index] != null;
}
@Override
public Object next() {
if (this.hasNext()) {
return books[index++];
}
return null;
}
}
// Collection Interface
interface BookCollection {
Iterator createIterator();
}
// Concrete Collection (Book Collection)
class BookList implements BookCollection {
private Book[] books;
private int size;
public BookList(int capacity) {
books = new Book[capacity];
size = 0;
}
public void addBook(Book book) {
if (size < books.length) {
books[size++] = book;
}
}
@Override
public Iterator createIterator() {
return new BookIterator(books);
}
}
// Book Class
class Book {
private String title;
private String author;
public Book(String title, String author) {
this.title = title;
this.author = author;
}
@Override
public String toString() {
return "Book [Title: " + title + ", Author: " + author + "]";
}
}
public class IteratorPatternExample {
public static void main(String[] args) {
BookList bookList = new BookList(5);
bookList.addBook(new Book("The Catcher in the Rye", "J.D. Salinger"));
bookList.addBook(new Book("To Kill a Mockingbird", "Harper Lee"));
bookList.addBook(new Book("1984", "George Orwell"));
Iterator iterator = bookList.createIterator();
System.out.println("Books in the collection:");
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
ব্যাখ্যা:
- Iterator Interface: এটি দুটি মেথড ডিফাইন করে:
hasNext()যা পরবর্তী উপাদান আছে কিনা তা চেক করে, এবংnext()যা পরবর্তী উপাদান ফেরত দেয়। - BookIterator: এটি
Iteratorইন্টারফেসের বাস্তবায়ন এবং এটি বইয়ের তালিকায় ভ্রমণ করার জন্যhasNext()এবংnext()মেথড ডিফাইন করে। - BookList: এটি একটি BookCollection যা একটি বইয়ের তালিকা সংরক্ষণ করে এবং
createIterator()মেথডের মাধ্যমেBookIteratorপ্রদান করে। - Book Class: এটি বইয়ের তথ্য সংরক্ষণ করে (যেমন: নাম এবং লেখক) এবং এটি একটি
toString()মেথড প্রদান করে যাতে বইয়ের তথ্য সুন্দরভাবে প্রিন্ট করা যায়।
আউটপুট:
Books in the collection:
Book [Title: The Catcher in the Rye, Author: J.D. Salinger]
Book [Title: To Kill a Mockingbird, Author: Harper Lee]
Book [Title: 1984, Author: George Orwell]
Iterator Pattern এর সুবিধা:
- Encapsulation of Data: Iterator Pattern ডেটা স্ট্রাকচারের অভ্যন্তরীণ কাঠামো লুকিয়ে রাখে, ফলে ব্যবহারকারীরা ইটারেটরের মাধ্যমে ডেটার উপাদানগুলির উপর কাজ করতে পারে এবং ডেটা স্ট্রাকচারের বাস্তবায়ন জানার প্রয়োজন পড়ে না।
- Uniform Access: বিভিন্ন ধরনের ডেটা স্ট্রাকচারের উপর একীভূতভাবে ভ্রমণ করতে পারে। উদাহরণস্বরূপ, একটি অ্যারে বা লিঙ্কড লিস্টে একই ইন্টারফেস ব্যবহার করে ভ্রমণ করা যায়।
- Simplifies Collection Access: ইটারেটর ব্যবহার করে ডেটা স্ট্রাকচারগুলির মধ্যে একে একে উপাদান ভ্রমণ করা সহজ এবং কোডের পুনঃব্যবহারযোগ্যতা বাড়ে।
Iterator Pattern এর সীমাবদ্ধতা:
- Extra Overhead: কখনও কখনও, Iterator Pattern এর প্রয়োগ অতিরিক্ত জটিলতা এবং ওভারহেড সৃষ্টি করতে পারে, বিশেষ করে ছোট বা সোজা ডেটা স্ট্রাকচারের জন্য।
- Limited Flexibility: Iterator সাধারণত একটি সুনির্দিষ্ট ধরনের ভ্রমণ পদ্ধতি প্রদান করে এবং সেটিকে পরিবর্তন করার জন্য পুনরায় Iterator ইন্টারফেস তৈরি করতে হতে পারে।
সারাংশ
Iterator Pattern হল একটি শক্তিশালী ডিজাইন প্যাটার্ন যা ডেটা স্ট্রাকচারের উপাদানগুলির উপর একে একে ভ্রমণ করার জন্য একটি সঙ্গতিপূর্ণ এবং নমনীয় পদ্ধতি প্রদান করে। এটি ডেটা স্ট্রাকচার এবং তাদের ভ্রমণের মধ্যে বিভাজন তৈরি করে, যার ফলে কোডটি আরও রিডেবল এবং বজায় রাখার উপযোগী হয়। এটি Java Collections Framework তে ব্যবহৃত হয়, যেমন List, Set, এবং Map এর উপাদান ভ্রমণ করতে।
Mediator Pattern হল একটি আচারিক (behavioral) ডিজাইন প্যাটার্ন যা একাধিক অবজেক্টের মধ্যে যোগাযোগ পরিচালনার জন্য একটি মধ্যস্থতাকারী (mediator) অবজেক্ট ব্যবহার করে। এর মূল উদ্দেশ্য হল একাধিক অবজেক্টের মধ্যে সরাসরি যোগাযোগ কমানো এবং সেই যোগাযোগের জন্য একটি একক কেন্দ্রীয় স্থান তৈরি করা, যাতে সমস্ত অবজেক্ট একে অপরের সাথে সরাসরি যোগাযোগ না করে, বরং মধ্যস্থতাকারীকে ব্যবহার করে।
Mediator Pattern এর মূল সুবিধা:
- Reduced Complexity: একাধিক অবজেক্টের মধ্যে সরাসরি যোগাযোগ কমিয়ে দেয়, ফলে সিস্টেমের জটিলতা কমে।
- Centralized Communication: সব ধরনের যোগাযোগ একটি কেন্দ্রীয় জায়গায় চলে আসে, যা কোডের রক্ষণাবেক্ষণ এবং টেস্টিং সহজ করে।
- Loose Coupling: অবজেক্টগুলির মধ্যে সম্পর্ক অনেকটাই শিথিল (loose) হয়, কারণ তারা শুধুমাত্র mediator এর মাধ্যমে যোগাযোগ করে।
Mediator Pattern এর ব্যবহার:
- Chat Systems: যেখানে একাধিক ব্যবহারকারী (users) একে অপরের সাথে যোগাযোগ করতে চান, তবে তারা সরাসরি একে অপরের সাথে যোগাযোগ না করে, একটি mediator (যেমন, সার্ভার) এর মাধ্যমে যোগাযোগ করে।
- Air Traffic Control: যেখানে বিমানগুলি সরাসরি একে অপরের সাথে যোগাযোগ না করে, তবে air traffic controller এর মাধ্যমে যোগাযোগ করে।
1. Mediator Pattern এর মৌলিক উপাদান
Mediator Pattern তিনটি প্রধান উপাদান নিয়ে গঠিত:
- Mediator: একটি ইন্টারফেস যা অবজেক্টগুলির মধ্যে যোগাযোগ পরিচালনা করে।
- ConcreteMediator: এটি Mediator ইন্টারফেসের বাস্তবায়ন এবং একাধিক colleague অবজেক্টের মধ্যে যোগাযোগকে নিয়ন্ত্রণ করে।
- Colleague: এটি এমন অবজেক্ট যা Mediator এর সাথে যোগাযোগ করে এবং নিজের কাজ সম্পন্ন করার জন্য Mediator কে অবহিত করে।
2. Mediator Pattern এর বাস্তবায়ন
ধরা যাক একটি chat room এর উদাহরণ যেখানে ব্যবহারকারীরা (users) একে অপরের সাথে কথা বলে, তবে তারা সরাসরি একে অপরের সাথে যোগাযোগ না করে, একটি mediator (chat room) এর মাধ্যমে কথোপকথন করে।
উদাহরণ: Mediator Pattern - Chat Room
// Mediator Interface
interface ChatRoomMediator {
void sendMessage(String message, User user);
void addUser(User user);
}
// ConcreteMediator
class ChatRoom implements ChatRoomMediator {
private List<User> users;
public ChatRoom() {
this.users = new ArrayList<>();
}
@Override
public void sendMessage(String message, User user) {
for (User u : users) {
if (u != user) {
u.receiveMessage(message);
}
}
}
@Override
public void addUser(User user) {
users.add(user);
}
}
// Colleague
abstract class User {
protected ChatRoomMediator mediator;
protected String name;
public User(ChatRoomMediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public abstract void sendMessage(String message);
public abstract void receiveMessage(String message);
}
// ConcreteColleague
class ConcreteUser extends User {
public ConcreteUser(ChatRoomMediator mediator, String name) {
super(mediator, name);
}
@Override
public void sendMessage(String message) {
System.out.println(name + " sends: " + message);
mediator.sendMessage(message, this);
}
@Override
public void receiveMessage(String message) {
System.out.println(name + " receives: " + message);
}
}
public class MediatorPatternExample {
public static void main(String[] args) {
ChatRoomMediator mediator = new ChatRoom();
User user1 = new ConcreteUser(mediator, "Alice");
User user2 = new ConcreteUser(mediator, "Bob");
User user3 = new ConcreteUser(mediator, "Charlie");
mediator.addUser(user1);
mediator.addUser(user2);
mediator.addUser(user3);
user1.sendMessage("Hello Bob!");
user2.sendMessage("Hi Alice! How are you?");
user3.sendMessage("Hey everyone!");
}
}
ব্যাখ্যা:
- ChatRoomMediator: এটি একটি ইন্টারফেস যা মেসেজ পাঠানোর জন্য
sendMessageএবং ব্যবহারকারী যোগ করার জন্যaddUserমেথড সরবরাহ করে। - ChatRoom: এটি ChatRoomMediator এর কনক্রিট ক্লাস, যা সকল ব্যবহারকারীকে পরিচালনা করে এবং মেসেজগুলি একে অপরের কাছে পাঠায়।
- User: এটি একটি অ্যাবস্ট্রাক্ট ক্লাস যা sendMessage এবং receiveMessage মেথড সংজ্ঞায়িত করে, যা কনক্রিট ব্যবহারকারীদের মাধ্যমে বাস্তবায়িত হয়।
- ConcreteUser: এটি একটি বাস্তব ব্যবহারকারী ক্লাস যা ChatRoom এর মাধ্যমে মেসেজ পাঠায় এবং গ্রহণ করে।
আউটপুট:
Alice sends: Hello Bob!
Bob receives: Hello Bob!
Charlie receives: Hello Bob!
Bob sends: Hi Alice! How are you?
Alice receives: Hi Alice! How are you?
Charlie receives: Hi Alice! How are you?
Charlie sends: Hey everyone!
Alice receives: Hey everyone!
Bob receives: Hey everyone!
3. Mediator Pattern এর সুবিধা
- Loose Coupling: Mediator Pattern অবজেক্টগুলির মধ্যে যোগাযোগের জন্য একটি কেন্দ্রীয় স্থান ব্যবহার করে, যার ফলে অবজেক্টগুলির মধ্যে সরাসরি যোগাযোগ কমে যায় এবং শিথিল সম্পর্ক তৈরি হয়।
- Simplified Communication: একাধিক অবজেক্টের মধ্যে যোগাযোগ পরিচালনা করতে mediator ব্যবহার করা সহজ হয়।
- Centralized Control: যোগাযোগের সমস্ত লজিক একটি কেন্দ্রীয় স্থানে থাকে, যা রক্ষণাবেক্ষণ এবং কোডের পরিবর্তন সহজ করে তোলে।
4. Mediator Pattern এর বাস্তব প্রয়োগ
Mediator Pattern বিভিন্ন ক্ষেত্রে ব্যবহৃত হয় যেখানে একাধিক অবজেক্টের মধ্যে যোগাযোগে কোনো ধরনের জটিলতা এবং শিথিল সম্পর্ক তৈরি করতে হয়। কিছু বাস্তব প্রয়োগের উদাহরণ:
- Chat Applications: যেখানে একাধিক ব্যবহারকারী একে অপরের সাথে যোগাযোগ করতে পারে, তবে তারা সরাসরি একে অপরের সাথে যোগাযোগ না করে, mediator (chat server) এর মাধ্যমে যোগাযোগ করে।
- UI Components: যেখানে বিভিন্ন UI কম্পোনেন্ট (যেমন টেক্সট বক্স, বাটন, চেকবক্স) একে অপরের সাথে যোগাযোগ করে এবং mediator (কন্ট্রোলার) সমস্ত ইন্টারঅ্যাকশন পরিচালনা করে।
- Air Traffic Control: বিমানগুলির মধ্যে যোগাযোগ পরিচালনা করতে একটি mediator (air traffic controller) ব্যবহার করা হয়।
Mediator Pattern হল একটি শক্তিশালী ডিজাইন প্যাটার্ন যা একাধিক অবজেক্টের মধ্যে যোগাযোগকে সহজ এবং শিথিল করে। এটি যোগাযোগের জন্য একটি একক কেন্দ্রীয় অবজেক্ট ব্যবহার করে এবং কোডের রক্ষণাবেক্ষণ এবং উন্নয়নকে আরও সহজ করে তোলে। Java তে এটি খুব সহজেই বাস্তবায়ন করা যায় এবং এটি chat systems, UI components, air traffic control, এবং অন্যান্য জটিল সিস্টেমে কার্যকরভাবে ব্যবহার করা যেতে পারে।
Memento Pattern একটি বিহেভিয়রাল ডিজাইন প্যাটার্ন, যা একটি অবজেক্টের অভ্যন্তরীণ অবস্থানকে সংরক্ষণ করে এবং সেই অবস্থাকে পরে পুনরুদ্ধার করার সুযোগ দেয়। এটি মূলত অবজেক্টের ইতিহাস ট্র্যাক করার জন্য ব্যবহৃত হয়, যেমন একটি অবজেক্টের স্থিতি (state) পুনরুদ্ধারের প্রয়োজন হলে, আপনি সেই স্থিতিকে রিস্টোর করতে পারেন।
Memento Pattern মূলত তিনটি উপাদান নিয়ে কাজ করে:
- Originator: এটি এমন একটি অবজেক্ট যার অবস্থা (state) সংরক্ষণ করা এবং পুনরুদ্ধার করা হয়।
- Memento: এটি অবজেক্টের একটি কপি যা অবজেক্টের বর্তমান অবস্থাকে ধারণ করে।
- Caretaker: এটি মেমেন্টো অবজেক্টটি সংরক্ষণ করে এবং মূল অবজেক্টের অবস্থান পরিবর্তন করতে সাহায্য করে।
Memento Pattern এর প্রয়োজনীয়তা
যখন কোনো অবজেক্টের অবস্থান বারবার পরিবর্তিত হয় এবং আপনি সেই অবস্থা রক্ষা করতে চান, কিন্তু এটি অবজেক্টের অভ্যন্তরীণ প্রাইভেট ডেটা না জানিয়ে তা করতে চান, তখন Memento Pattern ব্যবহার করা হয়। এটি কার্যকরীভাবে "undo" বা "rollback" ফিচার তৈরি করতে সাহায্য করে।
Memento Pattern এর কাঠামো
- Originator: অবজেক্টের মধ্যে ডেটা বা স্টেট সংরক্ষণ করা হয়।
- Memento: অবজেক্টের স্টেট বা অবস্থার কপি।
- Caretaker: স্টেট বা অবস্থাটি পরিচালনা ও সংরক্ষণ করে।
উদাহরণ: Memento Pattern
ধরা যাক, আমরা একটি TextEditor (টেক্সট এডিটর) তৈরি করছি, যেখানে ব্যবহারকারী টেক্সট লিখছে এবং তার পর সেই টেক্সটের পূর্ববর্তী অবস্থায় ফিরে যেতে পারবে।
1. Originator Class (TextEditor)
TextEditor হল সেই ক্লাস যা তার অবস্থা (যেমন টেক্সট) সংরক্ষণ করে এবং পুনরুদ্ধার করতে সাহায্য করে।
public class TextEditor {
private String text;
public TextEditor(String text) {
this.text = text;
}
// Method to set text
public void setText(String text) {
this.text = text;
}
// Method to get text
public String getText() {
return text;
}
// Method to create a Memento (save state)
public Memento save() {
return new Memento(text);
}
// Method to restore state from Memento
public void restore(Memento memento) {
this.text = memento.getSavedState();
}
}
2. Memento Class
Memento ক্লাস অবজেক্টের অবস্থা সংরক্ষণ করে। এটি মূল অবজেক্টের অভ্যন্তরীণ তথ্য ধারণ করে।
public class Memento {
private final String savedState;
// Constructor to save state
public Memento(String state) {
this.savedState = state;
}
// Getter for saved state
public String getSavedState() {
return savedState;
}
}
3. Caretaker Class
Caretaker ক্লাস একটি বা একাধিক মেমেন্টো সংরক্ষণ করে। এটি মেমেন্টো অবজেক্টের সাথে সম্পর্কিত নয়, বরং শুধু সংরক্ষণ এবং পুনরুদ্ধারের দায়িত্ব পালন করে।
import java.util.Stack;
public class Caretaker {
private Stack<Memento> mementoList = new Stack<>();
// Method to add Memento to the list
public void addMemento(Memento memento) {
mementoList.push(memento);
}
// Method to get the last saved Memento
public Memento getLastMemento() {
if (!mementoList.isEmpty()) {
return mementoList.pop();
}
return null;
}
}
4. Testing the Memento Pattern
এখন আমরা সবকটি ক্লাস ব্যবহার করে একটি উদাহরণ দেখব যেখানে টেক্সট এডিটর একটি টেক্সট স্টেট সেভ করে এবং পরে সেই স্টেট পুনরুদ্ধার করবে।
public class MementoPatternExample {
public static void main(String[] args) {
// Create a TextEditor and set initial text
TextEditor editor = new TextEditor("Hello");
System.out.println("Initial Text: " + editor.getText());
// Create a Caretaker to manage mementos
Caretaker caretaker = new Caretaker();
// Save the state
caretaker.addMemento(editor.save());
editor.setText("Hello, world!");
System.out.println("Updated Text: " + editor.getText());
// Restore the state
editor.restore(caretaker.getLastMemento());
System.out.println("Restored Text: " + editor.getText());
}
}
আউটপুট:
Initial Text: Hello
Updated Text: Hello, world!
Restored Text: Hello
এখানে:
- প্রথমে আমরা
TextEditorতৈরি করেছি এবং সেটির প্রথম টেক্সট"Hello"সেট করেছি। - তারপর আমরা
Caretakerদিয়ে সেই স্টেট সেভ করেছি। - এরপর আমরা টেক্সট পরিবর্তন করেছি, কিন্তু তারপর আগের টেক্সট
"Hello"-তে ফিরে এসেছি, যাrestore()মেথডের মাধ্যমে সম্ভব হয়েছে।
Memento Pattern এর ব্যাখ্যা:
- TextEditor (Originator): এটি আসল অবজেক্ট যার স্টেট (অর্থাৎ টেক্সট) সংরক্ষণ করা এবং পুনরুদ্ধার করা হয়।
- Memento: এটি
TextEditorএর বর্তমান অবস্থা (টেক্সট) সংরক্ষণ করে এবং কোনো অন্য ক্লাসে পাঠানো বা পুনরুদ্ধার করা যায়। - Caretaker: এটি
Mementoসংরক্ষণ করে এবং পরে সেইMementoথেকে অবস্থা পুনরুদ্ধার করতে সাহায্য করে।CaretakerকখনোMementoক্লাসের ভিতরের স্টেট জানে না।
Advantages of Memento Pattern:
- Encapsulation of State: Memento Pattern অবজেক্টের অভ্যন্তরীণ অবস্থাকে সুরক্ষিত রাখে এবং শুধুমাত্র প্রয়োজনীয় অংশকেই অ্যাক্সেস করার সুযোগ দেয়।
- Undo/Redo Functionality: এটি "undo" বা "redo" অপশন তৈরি করতে সহায়ক, কারণ পূর্ববর্তী অবস্থায় ফিরে যাওয়ার জন্য আমরা সহজেই অবজেক্টের পুরানো স্টেট ব্যবহার করতে পারি।
- Separation of Concerns:
Caretakerঅবজেক্টটি শুধুমাত্র মেমেন্টো সংরক্ষণ এবং পুনরুদ্ধারের কাজ করে, যা মূল অবজেক্ট (Originator) থেকে আলাদা। এটি কোডের পরিষ্কারতা ও রক্ষণাবেক্ষণযোগ্যতা বৃদ্ধি করে।
Disadvantages:
- Memory Consumption: মেমেন্টো ক্লাসটি অবজেক্টের একটি কপি সংরক্ষণ করে, যা অতিরিক্ত মেমরি ব্যবহার করতে পারে, বিশেষত যখন বড় বা জটিল অবজেক্টের অবস্থান সংরক্ষণ করতে হয়।
- Complexity: অনেক সময় এটি অতিরিক্ত কোড তৈরি করে, কারণ একাধিক মেমেন্টো অবজেক্ট তৈরি হতে পারে এবং সেগুলি সংরক্ষণ ও পুনরুদ্ধার করতে অনেক কোডের প্রয়োজন হতে পারে।
সারাংশ
Memento Pattern একটি শক্তিশালী ডিজাইন প্যাটার্ন যা অবজেক্টের স্টেট সংরক্ষণ এবং পরে পুনরুদ্ধারের কাজ করে। এটি মূলত undo/redo ফিচারের জন্য ব্যবহৃত হয় এবং অবজেক্টের অভ্যন্তরীণ অবস্থা সংরক্ষণে সহায়তা করে। Originator অবজেক্ট, Memento ক্লাস এবং Caretaker ক্লাসের সাহায্যে, আমরা অবজেক্টের অভ্যন্তরীণ অবস্থা সংরক্ষণ এবং পুনরুদ্ধার করতে পারি। Memento Pattern এফেক্টিভভাবে স্টেট ম্যানেজমেন্ট, গেমস, ডেটা রিকভারি এবং অন্যান্য সিস্টেমের জন্য ব্যবহার করা যায়।
Observer Pattern হল একটি Behavioral Design Pattern যা একাধিক অবজারভার (observers) বা সদস্যকে একটি অবজেক্টের (subject) অবস্থা পরিবর্তন সম্পর্কে অবহিত করার জন্য ব্যবহৃত হয়। যখন একটি অবজেক্টের অবস্থা পরিবর্তিত হয়, তখন সেই পরিবর্তন সকল অবজারভারদের জানিয়ে দেওয়া হয়। এটি one-to-many dependency সম্পর্ক তৈরি করে, যেখানে একটি অবজেক্টের পরিবর্তন অন্যান্য একাধিক অবজেক্টকে প্রভাবিত করে।
এটি সাধারণত ব্যবহার করা হয় এমন সিস্টেমে যেখানে একটি অবজেক্টের পরিবর্তন বা ঘটনাটি (event) অন্যান্য অবজেক্টগুলির উপর সরাসরি প্রভাব ফেলে, যেমন UI updates, event-driven systems, model-view-controller (MVC) ডিজাইন, ইত্যাদি।
1. Observer Pattern এর বৈশিষ্ট্য
- One-to-many Dependency: একেকটি সিস্টেমের Subject (বা Observable) হতে পারে একাধিক Observers বা পর্যবেক্ষক। যখন Subject এর অবস্থা পরিবর্তিত হয়, তখন সেটি সমস্ত Observers কে অবহিত করে।
- Loose Coupling: Observer এবং Subject একে অপরের থেকে আলাদা থাকে এবং তাদের মধ্যে খুব কম সম্পর্ক থাকে। Subject এর অবস্থা পরিবর্তন হলেও, Observer এর কাজ আগের মতো থাকে।
- Dynamic Subscription: Observer Pattern এ Observer গুলো ডায়নামিকভাবে Subject এর সাথে যুক্ত বা বিচ্ছিন্ন হতে পারে।
2. Observer Pattern এর ব্যবহারের ক্ষেত্র
- Event handling systems: GUI (Graphical User Interface) অ্যাপ্লিকেশন যেমন: Swing, JavaFX বা Android UI, যেখানে ইউজারের ক্রিয়া (event) এর উপর ভিত্তি করে ডাটা আপডেট করা হয়।
- Model-View-Controller (MVC): UI এর পরিবর্তন সম্পর্কে Model কে অবহিত করা, বা vice versa।
- Real-time applications: যেমন একাধিক ক্লায়েন্টের জন্য আপডেট বার্তা পাঠানো (live feeds, notifications)।
- State Change Notification: একটি অবজেক্টের স্টেট পরিবর্তনের সাথে সাথে অন্য অবজেক্টদের তা জানানো।
3. Observer Pattern এর স্ট্রাকচার
Observer Pattern এর স্ট্রাকচার সাধারণত তিনটি প্রধান উপাদান থেকে গঠিত হয়:
- Subject (Observable): এটি সেই অবজেক্ট যা তার অবস্থা পরিবর্তন ঘটায় এবং Observer গুলোকে আপডেট করার জন্য প্রস্তুত থাকে।
- Observer: এটি সেই অবজেক্ট যা Subject থেকে বার্তা পেয়ে তার অবস্থান আপডেট করে।
- ConcreteSubject: এটি Subject এর বাস্তবায়ন, যেখানে অবস্থা পরিবর্তন ঘটায়।
- ConcreteObserver: এটি Observer এর বাস্তবায়ন, যা Subject এর পরিবর্তনের উপর ভিত্তি করে নিজেকে আপডেট করে।
4. Observer Pattern এর উদাহরণ
ধরা যাক, একটি সিস্টেমে একটি WeatherStation ক্লাস আছে যা অবস্থা পরিবর্তন করলে সব Display (Observers) কে তথ্য প্রদান করবে। এখানে WeatherStation হল Subject, এবং বিভিন্ন ডিসপ্লে ইউনিট (যেমন PhoneDisplay, LCDDisplay) হল Observer।
Observer Pattern এর কোড উদাহরণ:
import java.util.ArrayList;
import java.util.List;
// Observer Interface
interface Observer {
void update(float temperature, float humidity, float pressure);
}
// Subject Interface
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// Concrete Subject
class WeatherStation implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherStation() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
public void setWeatherData(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
notifyObservers(); // Notify all observers when data changes
}
}
// Concrete Observer 1
class PhoneDisplay implements Observer {
@Override
public void update(float temperature, float humidity, float pressure) {
System.out.println("Phone Display: Weather Update -> Temperature: " + temperature
+ ", Humidity: " + humidity + ", Pressure: " + pressure);
}
}
// Concrete Observer 2
class LCDDisplay implements Observer {
@Override
public void update(float temperature, float humidity, float pressure) {
System.out.println("LCD Display: Weather Update -> Temperature: " + temperature
+ ", Humidity: " + humidity + ", Pressure: " + pressure);
}
}
public class Main {
public static void main(String[] args) {
// Create WeatherStation (Subject)
WeatherStation weatherStation = new WeatherStation();
// Create observers
PhoneDisplay phoneDisplay = new PhoneDisplay();
LCDDisplay lcdDisplay = new LCDDisplay();
// Register observers to WeatherStation
weatherStation.registerObserver(phoneDisplay);
weatherStation.registerObserver(lcdDisplay);
// Simulate weather data change and notify observers
weatherStation.setWeatherData(30.4f, 65f, 1013f); // Data update and notify
System.out.println();
// Unregister one observer and update again
weatherStation.removeObserver(phoneDisplay);
weatherStation.setWeatherData(28.2f, 70f, 1012f); // Data update and notify
}
}
Output:
Phone Display: Weather Update -> Temperature: 30.4, Humidity: 65.0, Pressure: 1013.0
LCD Display: Weather Update -> Temperature: 30.4, Humidity: 65.0, Pressure: 1013.0
LCD Display: Weather Update -> Temperature: 28.2, Humidity: 70.0, Pressure: 1012.0
ব্যাখ্যা:
- WeatherStation (Subject) যখন setWeatherData() মেথডে নতুন ডেটা সেট করে, তখন এটি তার সকল নিবন্ধিত Observer (যেমন:
PhoneDisplayএবংLCDDisplay) কে notifyObservers() মেথডের মাধ্যমে অবহিত করে। - PhoneDisplay এবং LCDDisplay (Concrete Observers) তাদের
update()মেথডের মাধ্যমে নতুন ডেটা পায় এবং তা প্রদর্শন করে। - একটি Observer (
PhoneDisplay) কে removeObserver() মেথড দিয়ে রিমুভ করার পর, পরবর্তী ডেটা পরিবর্তনের সময় তা আপডেট পায় না।
5. Observer Pattern এর সুবিধা ও অসুবিধা
সুবিধা:
- Loose Coupling: Observer Pattern ক্লায়েন্ট এবং সাবজেক্টের মধ্যে স্বল্প সম্পর্ক রাখে। একটি সাবজেক্টে পরিবর্তন হলে তার কোনো প্রভাব Observer গুলিতে হয়, তবে তারা একে অপরের সাথে সরাসরি যোগাযোগ করে না।
- Dynamic Subscription: অবজারভাররা ডায়নামিকভাবে সাবজেক্টের সাথে যুক্ত বা বিচ্ছিন্ন হতে পারে।
- Reusability: একটি Observer pattern implementation একাধিক প্রসঙ্গে পুনরায় ব্যবহার করা যায়, যা সফটওয়্যার সিস্টেমের নমনীয়তা এবং রিইউজেবল কোড তৈরি করে।
অসুবিধা:
- Memory Leaks: যদি Observer গুলি সাবজেক্ট থেকে বিচ্ছিন্ন না হয়, তবে এটি memory leak সৃষ্টি করতে পারে, কারণ সাবজেক্ট তাদের রেফারেন্স ধরে রাখে।
- Complexity: অনেক Observer হলে সিস্টেম জটিল হতে পারে এবং Observer গুলির অনেকবার আপডেট হওয়া সফটওয়্যারের কর্মক্ষমতা কমিয়ে দিতে পারে।
- Notification Overhead: অনেক Observer থাকলে একসাথে অনেক নোটিফিকেশন পাঠানো যেতে পারে, যা সিস্টেমের পারফরম্যান্সে প্রভাব ফেলতে পারে।
Observer Pattern হল একটি শক্তিশালী ডিজাইন প্যাটার্ন যা ক্লায়েন্ট এবং সাবজেক্টের মধ্যে লুজ কপ্লিং (Loose Coupling) তৈরি করে এবং একাধিক অবজারভারদের মধ্যে অবস্থা পরিবর্তনের বার্তা প্রেরণ করার জন্য ব্যবহৃত হয়। এটি এমন সিস্টেমে খুবই কার্যকরী যেখানে অনেক অবজারভার একই সময়ে পরিবর্তন বা আপডেট পেতে চায়, যেমন গেম ডেভেলপমেন্ট, UI অ্যাপ্লিকেশন এবং রিয়েল-টাইম সিস্টেম।
Java তে Observer Pattern বাস্তবায়ন সহজ এবং শক্তিশালী। এটি ডিজাইন প্যাটার্নের মধ্যে একটি গুরুত্বপূর্ণ ভূমিকা পালন করে এবং সিস্টেমের ফ্লেক্সিবিলিটি এবং স্কেলেবিলিটি বৃদ্ধি করে।
State Pattern কি?
State Pattern হল একটি Behavioral Design Pattern যা অবজেক্টের অভ্যন্তরীণ অবস্থা (state) পরিবর্তিত হওয়ার সাথে সাথে তার আচরণ পরিবর্তন করার কৌশল প্রদান করে। এই প্যাটার্নে, একটি অবজেক্টের অবস্থা পরিবর্তন হলে তার আচরণও পরিবর্তিত হয়ে যায়, যেটি state transitions এর মাধ্যমে পরিচালিত হয়।
State Pattern মূলত ব্যবহার করা হয় যখন একটি অবজেক্টের আচরণ তার অবস্থা অনুযায়ী পরিবর্তিত হয় এবং সেই অবস্থার মধ্যে যেকোনো একটিতে থাকা অবস্থায়, অবজেক্টটি বিভিন্ন আচরণ প্রদর্শন করতে পারে।
State Pattern এর উপাদান:
- Context: এটি একটি ক্লাস যা বর্তমান অবস্থা (state) ধারণ করে এবং সঠিক আচরণে ট্রানজিশন করার জন্য স্টেট অবজেক্টের সাথে কাজ করে।
- State: এটি একটি ইন্টারফেস বা অ্যাবস্ট্রাক্ট ক্লাস যা বর্তমান অবস্থার জন্য সংজ্ঞায়িত আচরণ নির্ধারণ করে।
- ConcreteState: এটি State ইন্টারফেস বা ক্লাসের কনক্রিট বাস্তবায়ন যেখানে বর্তমান অবস্থার জন্য সঠিক আচরণগুলি সংজ্ঞায়িত করা হয়।
State Pattern এর উদাহরণ
ধরা যাক, একটি TCP Connection সিস্টেম তৈরি করতে হবে যেখানে বিভিন্ন অবস্থা থাকে, যেমন Established, Closed, Listening। এই সিস্টেমে TCPConnection ক্লাসের অবস্থা পরিবর্তিত হলে তার আচরণও পরিবর্তিত হবে, যেমন Sending Data, Closing Connection, ইত্যাদি।
Step 1: State Interface
// State Interface
public interface TCPConnectionState {
void handle(TCPConnection connection);
}
Step 2: ConcreteState Classes
// ConcreteState: Established State
public class EstablishedState implements TCPConnectionState {
@Override
public void handle(TCPConnection connection) {
System.out.println("Handling the Established state.");
// Transition to another state if needed
connection.setState(new ClosingState()); // Transition to Closing State
}
}
// ConcreteState: Closed State
public class ClosedState implements TCPConnectionState {
@Override
public void handle(TCPConnection connection) {
System.out.println("Handling the Closed state.");
// Transition to another state if needed
connection.setState(new ListeningState()); // Transition to Listening State
}
}
// ConcreteState: Listening State
public class ListeningState implements TCPConnectionState {
@Override
public void handle(TCPConnection connection) {
System.out.println("Handling the Listening state.");
// Transition to another state if needed
connection.setState(new EstablishedState()); // Transition to Established State
}
}
Step 3: Context (TCPConnection)
// Context Class
public class TCPConnection {
private TCPConnectionState state;
public TCPConnection() {
// Initially, set the state to Listening
this.state = new ListeningState();
}
// Set the current state
public void setState(TCPConnectionState state) {
this.state = state;
}
// Perform actions based on the current state
public void handleRequest() {
state.handle(this);
}
}
Step 4: Client
public class StatePatternExample {
public static void main(String[] args) {
// Create a TCPConnection object
TCPConnection connection = new TCPConnection();
// Handle requests, which will trigger state transitions
connection.handleRequest(); // Handling the Listening state.
connection.handleRequest(); // Handling the Established state.
connection.handleRequest(); // Handling the Closing state.
}
}
ব্যাখ্যা:
- State Interface:
TCPConnectionStateএকটি ইন্টারফেস যা সব ধরনের স্টেটের জন্য আচরণ সংজ্ঞায়িত করে। - ConcreteState Classes:
EstablishedState,ClosedState, এবংListeningStateহল ConcreteState ক্লাস, যেখানে প্রতিটি স্টেটেhandle()মেথডের মাধ্যমে কার্যক্রম নির্ধারণ করা হয়। - Context (TCPConnection):
TCPConnectionক্লাসটি বর্তমান অবস্থা সংরক্ষণ করে এবংhandleRequest()মেথডের মাধ্যমে সঠিক স্টেটের আচরণ ট্রিগার করে। স্টেট পরিবর্তন করার জন্যsetState()মেথড ব্যবহার করা হয়।
State Pattern এর সুবিধা:
- State Transitions: এই প্যাটার্নটি অবজেক্টের মধ্যে স্টেট পরিবর্তনের ফলে আচরণের পরিবর্তনকে খুবই সহজ করে তোলে।
- Encapsulation: স্টেটের প্রতিটি পরিবর্তন এবং আচরণের বাস্তবায়ন আলাদা ক্লাসে রাখা হয়, যা কোডের পড়া এবং রক্ষণাবেক্ষণ সহজ করে তোলে।
- Extendable: নতুন স্টেট যুক্ত করা সহজ, কারণ শুধুমাত্র নতুন ConcreteState ক্লাস তৈরি করতে হবে এবং Context ক্লাসে কোন পরিবর্তন করতে হবে না।
- Flexibility: স্টেট পরিবর্তনের মাধ্যমে আচরণকে সহজে কাস্টমাইজ করা যায়।
State Pattern এর ব্যবহার:
- State Machine: এটি এমন জায়গায় ব্যবহার করা হয় যেখানে অনেক ধরণের অবস্থা এবং সেগুলোর মধ্যে ট্রানজিশন প্রয়োজন। যেমন TCP Connection স্টেট মেশিন, গেমের অবস্থা, ডিভাইসের বিভিন্ন অপারেশন ইত্যাদি।
- Workflow Management Systems: অনেক ধাপের প্রক্রিয়া যেখানে প্রতিটি ধাপ একটি নির্দিষ্ট অবস্থা নির্ধারণ করে এবং পরবর্তী ধাপে প্রবাহিত হয়।
- UI States: ইউজার ইন্টারফেসে বিভিন্ন অবস্থার মধ্যে অর্ডার পরিবর্তন, যেমন একটি বোতাম ক্লিক করার পরে অ্যাপ্লিকেশন একটি নতুন অবস্থায় প্রবাহিত হবে।
সারাংশ
State Pattern হল একটি Behavioral Design Pattern যা অবজেক্টের অভ্যন্তরীণ অবস্থার পরিবর্তনের সাথে সাথে তার আচরণ পরিবর্তন করতে সাহায্য করে। এটি স্টেট পরিবর্তনের জন্য অবজেক্টের আচরণ পরিবর্তন করে এবং স্টেটের অবস্থা অনুযায়ী সঠিক কর্মপদ্ধতি গ্রহণ করে। এটি কোডের রক্ষণাবেক্ষণ এবং এক্সটেনশন সহজ করে, কারণ নতুন স্টেটগুলি সরাসরি যুক্ত করা যায় এবং পুরনো কোডে কমপ্লেক্সিটি বৃদ্ধি না করে। State Pattern বিশেষভাবে উপযোগী যেখানে অবজেক্টের অনেকগুলি অবস্থার মধ্যে আচরণ পরিবর্তন করতে হয়।
Strategy Pattern হল একটি Behavioral Design Pattern, যা বিভিন্ন অ্যালগরিদম বা আচরণগুলিকে একে অপরের পরিবর্তে ব্যবহার করার সুযোগ প্রদান করে। এটি একটি ইন্টারফেস (Strategy) তৈরি করে যা বিভিন্ন Concrete Strategy ক্লাস দ্বারা বাস্তবায়িত হয়। Context ক্লাসটি Strategy ইন্টারফেসের একটি রেফারেন্স রাখে এবং প্রয়োজন অনুসারে বিভিন্ন Concrete Strategy ব্যবহার করে।
1. Strategy Pattern কী?
Strategy Pattern এর মূল উদ্দেশ্য হল একটি পরিবারের অ্যালগরিদমকে ইনকাপসুলেট করা এবং এগুলোকে একে অপরের পরিবর্তে ব্যবহার করার সুবিধা প্রদান করা। এটি ক্লায়েন্টকে নির্দিষ্ট অ্যালগরিদম বা আচরণ নির্বাচন করার ক্ষমতা দেয়, যা কোডের loose coupling নিশ্চিত করে এবং সহজে পরিবর্তনযোগ্য করে তোলে।
2. Strategy Pattern এর কাঠামো
Strategy Pattern তিনটি প্রধান উপাদান নিয়ে গঠিত:
- Strategy Interface: একটি সাধারণ ইন্টারফেস যা বিভিন্ন Concrete Strategy ক্লাসগুলি বাস্তবায়িত করে।
- Concrete Strategies: Strategy ইন্টারফেসের বিভিন্ন বাস্তবায়ন, যা বিভিন্ন অ্যালগরিদম বা আচরণ প্রতিনিধিত্ব করে।
- Context: এটি Strategy ইন্টারফেসের একটি রেফারেন্স রাখে এবং প্রয়োজন অনুযায়ী Concrete Strategy ব্যবহার করে।
3. Strategy Pattern এর উদাহরণ
ধরা যাক আমাদের একটি Payment System রয়েছে, যেখানে বিভিন্ন ধরনের পেমেন্ট গেটওয়ে (যেমন, ক্রেডিট কার্ড, পে-পাল, বিটকয়েন) ব্যবহার করা হতে পারে। আমরা Strategy Pattern ব্যবহার করে এই পেমেন্ট গেটওয়েগুলিকে ইনক্যাপসুলেট করতে পারি এবং সহজেই নতুন পেমেন্ট গেটওয়ে যোগ করতে পারি।
3.1. Strategy Pattern Implementation Example in Java
// Strategy Interface
interface PaymentStrategy {
void pay(int amount);
}
// Concrete Strategy: Credit Card Payment
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
private String cardHolder;
private String cvv;
public CreditCardPayment(String cardNumber, String cardHolder, String cvv) {
this.cardNumber = cardNumber;
this.cardHolder = cardHolder;
this.cvv = cvv;
}
@Override
public void pay(int amount) {
System.out.println(amount + " টাকা ক্রেডিট কার্ড দিয়ে পরিশোধ করা হলো।");
// বাস্তবায়নের অংশ: কার্ডের মাধ্যমে টাকা লেনদেনের কোড
}
}
// Concrete Strategy: PayPal Payment
class PayPalPayment implements PaymentStrategy {
private String email;
private String password;
public PayPalPayment(String email, String password) {
this.email = email;
this.password = password;
}
@Override
public void pay(int amount) {
System.out.println(amount + " টাকা পে-পাল দিয়ে পরিশোধ করা হলো।");
// বাস্তবায়নের অংশ: পে-পালের মাধ্যমে টাকা লেনদেনের কোড
}
}
// Concrete Strategy: Bitcoin Payment
class BitcoinPayment implements PaymentStrategy {
private String walletAddress;
public BitcoinPayment(String walletAddress) {
this.walletAddress = walletAddress;
}
@Override
public void pay(int amount) {
System.out.println(amount + " টাকা বিটকয়েন দিয়ে পরিশোধ করা হলো।");
// বাস্তবায়নের অংশ: বিটকয়েনের মাধ্যমে টাকা লেনদেনের কোড
}
}
// Context Class
class ShoppingCart {
private List<Item> items;
private PaymentStrategy paymentStrategy;
public ShoppingCart() {
this.items = new ArrayList<>();
}
public void addItem(Item item) {
items.add(item);
}
public void removeItem(Item item) {
items.remove(item);
}
public int calculateTotal() {
int total = 0;
for (Item item : items) {
total += item.getPrice();
}
return total;
}
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void checkout() {
int total = calculateTotal();
paymentStrategy.pay(total);
}
}
// Item Class
class Item {
private String name;
private int price;
public Item(String name, int price) {
this.name = name;
this.price = price;
}
public int getPrice() {
return price;
}
}
// Client Code
public class StrategyPatternDemo {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
Item item1 = new Item("ল্যাপটপ", 50000);
Item item2 = new Item("মাউস", 1500);
Item item3 = new Item("কীবোর্ড", 2000);
cart.addItem(item1);
cart.addItem(item2);
cart.addItem(item3);
// পেমেন্ট পদ্ধতি নির্বাচন
PaymentStrategy creditCardPayment = new CreditCardPayment("1234-5678-9012-3456", "জন ডো", "123");
PaymentStrategy payPalPayment = new PayPalPayment("john.doe@example.com", "password123");
PaymentStrategy bitcoinPayment = new BitcoinPayment("1A2b3C4d5E6f7G8h9I0j");
// ক্রেডিট কার্ড দিয়ে পেমেন্ট
cart.setPaymentStrategy(creditCardPayment);
cart.checkout();
System.out.println("----");
// পে-পাল দিয়ে পেমেন্ট
cart.setPaymentStrategy(payPalPayment);
cart.checkout();
System.out.println("----");
// বিটকয়েন দিয়ে পেমেন্ট
cart.setPaymentStrategy(bitcoinPayment);
cart.checkout();
}
}
3.2. উদাহরণের ব্যাখ্যা:
- PaymentStrategy: এটি একটি ইন্টারফেস যা pay() মেথড ঘোষণা করে। এটি বিভিন্ন পেমেন্ট গেটওয়েগুলির জন্য একটি সাধারণ ইন্টারফেস প্রদান করে।
- Concrete Strategies:
- CreditCardPayment: ক্রেডিট কার্ড দিয়ে পেমেন্ট করার বাস্তবায়ন।
- PayPalPayment: পে-পাল দিয়ে পেমেন্ট করার বাস্তবায়ন।
- BitcoinPayment: বিটকয়েন দিয়ে পেমেন্ট করার বাস্তবায়ন।
- ShoppingCart: এটি Context ক্লাস, যা PaymentStrategy এর একটি রেফারেন্স রাখে এবং পেমেন্ট সম্পাদনের জন্য checkout() মেথডে এটি ব্যবহার করে।
- Item: এটি একটি সাধারণ ক্লাস যা শপিং কার্টে যুক্ত হওয়া আইটেমগুলির প্রতিনিধিত্ব করে।
- StrategyPatternDemo: ক্লায়েন্ট কোড যেখানে আমরা শপিং কার্টে আইটেম যোগ করি, বিভিন্ন পেমেন্ট গেটওয়ে নির্বাচন করি এবং পেমেন্ট সম্পন্ন করি।
3.3. আউটপুট:
50000 টাকা ক্রেডিট কার্ড দিয়ে পরিশোধ করা হলো।
----
50000 টাকা পে-পাল দিয়ে পরিশোধ করা হলো।
----
50000 টাকা বিটকয়েন দিয়ে পরিশোধ করা হলো।
4. Strategy Pattern এর সুবিধা
- Loose Coupling: Strategy Pattern ক্লায়েন্ট কোড এবং কনক্রিট স্ট্র্যাটেজি ক্লাসগুলির মধ্যে loose coupling তৈরি করে, যা কোডের পুনঃব্যবহারযোগ্যতা এবং পরিবর্তন সহজ করে তোলে।
- বিভিন্ন অ্যালগরিদমের সহজ বিনিময়: বিভিন্ন আচরণ বা অ্যালগরিদম সহজেই পরিবর্তনযোগ্য এবং একে অপরের পরিবর্তে ব্যবহারযোগ্য।
- স্বচ্ছ এবং রিচার্জেবল কোড: কোডটি বেশি পরিষ্কার এবং মেইনটেইনেবল হয়, কারণ প্রতিটি স্ট্র্যাটেজি ক্লাসের মধ্যে পৃথক কাজ থাকে।
- Runtime এ আচরণ পরিবর্তন: পেমেন্ট পদ্ধতি runtime এ সহজেই পরিবর্তনযোগ্য।
5. Strategy Pattern এর অসুবিধা
- বহু ক্লাস: Strategy Pattern ব্যবহার করার ফলে অনেকগুলি ক্লাস তৈরি হতে পারে, যা কোড বেসকে জটিল করতে পারে।
- স্ট্র্যাটেজি নির্বাচন: সঠিক স্ট্র্যাটেজি নির্বাচন এবং ব্যবস্থাপনা কিছুটা জটিল হতে পারে, বিশেষ করে যদি অনেকগুলি স্ট্র্যাটেজি থাকে।
6. Strategy Pattern এর ব্যবহার
- পেমেন্ট সিস্টেম: বিভিন্ন পেমেন্ট গেটওয়ে (ক্রেডিট কার্ড, পে-পাল, বিটকয়েন) পরিচালনা করতে।
- গেমিং: বিভিন্ন গেমিং কৌশল বা AI আচরণ নিয়ন্ত্রণ করতে।
- ডাটা প্রসেসিং: বিভিন্ন ডাটা সোর্টিং বা প্রসেসিং অ্যালগরিদম নির্বাচন করতে।
- গ্রাফিক্স: বিভিন্ন গ্রাফিক্স রেন্ডারিং কৌশল ব্যবহার করতে।
7. Strategy Pattern এর তুলনা অন্য ডিজাইন প্যাটার্নের সাথে
| Feature | Strategy Pattern | State Pattern |
|---|---|---|
| Purpose | বিভিন্ন অ্যালগরিদম বা আচরণ একে অপরের পরিবর্তে ব্যবহার করা | অবজেক্টের অভ্যন্তরীণ অবস্থা অনুযায়ী আচরণ পরিবর্তন করা |
| Structure | Context, Strategy Interface, Concrete Strategies | Context, State Interface, Concrete States |
| Behavior Change | ক্লায়েন্ট দ্বারা নির্বাচিত | অবজেক্টের অভ্যন্তরীণ অবস্থা দ্বারা পরিবর্তিত |
| Use Case | পেমেন্ট গেটওয়ে, সোর্টিং অ্যালগরিদম | গেম স্টেট ম্যানেজমেন্ট, UI স্টেট পরিবর্তন |
সারাংশ
Strategy Pattern হল একটি Behavioral Design Pattern যা বিভিন্ন অ্যালগরিদম বা আচরণগুলিকে একে অপরের পরিবর্তে ব্যবহার করার সুযোগ প্রদান করে। এটি কোডের loose coupling নিশ্চিত করে, পুনঃব্যবহারযোগ্যতা বাড়ায় এবং কোডের readability উন্নত করে। Java তে Strategy Pattern ব্যবহার করে আমরা বিভিন্ন আচরণ বা অ্যালগরিদমগুলি সহজেই বিনিময়যোগ্য এবং নিয়ন্ত্রিত করতে পারি, যেমন পেমেন্ট গেটওয়ে, গেমিং কৌশল, ডাটা প্রসেসিং অ্যালগরিদম ইত্যাদি।
Strategy Pattern এর সাহায্যে, কোডটি আরও নমনীয় এবং রিচার্জেবল হয়, যা সফটওয়্যার ডেভেলপমেন্টে ভালো ডিজাইন এবং মেইনটেইনেবল কোড লিখতে সহায়ক।
Template Method Pattern একটি behavioral design pattern যা একটি অবজেক্টের কাজ করার মূল কাঠামোকে নির্দিষ্ট করে, কিন্তু কিছু ধাপের বাস্তবায়ন subclasses-এ delegating করে। এই প্যাটার্নটি মূলত একাধিক ধাপের সমন্বয়ে গঠিত একটি প্রক্রিয়া বা অ্যালগরিদমে ব্যবহৃত হয়, যেখানে নির্দিষ্ট কিছু অংশ সবার জন্য একরকম হয় এবং কিছু অংশ subclasses দ্বারা কাস্টমাইজড বা পরিবর্তিত হতে পারে।
Template Method Pattern এমন একটি প্যাটার্ন যেখানে সুপারক্লাসে একটি "template" মেথড থাকে, যা পুরো অ্যালগরিদম বা প্রক্রিয়ার কাঠামো নির্ধারণ করে, এবং সেগুলির কিছু অংশ সাবক্লাসে ডিফাইন করা হয়।
Template Method Pattern এর ধারণা
এই প্যাটার্নে, আমরা একটি abstract class তৈরি করি যা একটি মেথড নির্ধারণ করে, যা কিছু অবজেক্টের কাজে প্রধান কাঠামো হিসাবে কাজ করবে। এই মেথডের মধ্যে কিছু ধাপ abstract থাকে, যার বাস্তবায়ন subclasses-এ দেওয়া হয়। ফলে, subclasses তাদের নিজস্ব প্রয়োজন অনুযায়ী সেই ধাপগুলোর বাস্তবায়ন করতে পারে।
Template Method Pattern এর উপকারিতা
- Code Reusability: Template Method Pattern সাধারণত কোড পুনরায় ব্যবহারযোগ্যতা নিশ্চিত করে, কারণ মূল অ্যালগরিদমের কাঠামো সুপারক্লাসে থাকে এবং কেবলমাত্র কিছু অংশ subclasses দ্বারা পরিবর্তিত হয়।
- Flexibility: আপনি অ্যালগরিদমের মূল কাঠামো পরিবর্তন না করে বিভিন্ন ধাপের বাস্তবায়ন কাস্টমাইজ করতে পারেন।
- Control Over Execution: এই প্যাটার্নের মাধ্যমে মূল অ্যালগরিদমের বিভিন্ন অংশের কার্যক্রম নিয়ন্ত্রণ করা সম্ভব হয়, যার ফলে টেমপ্লেটের মধ্যে থাকা ধাপগুলো অবিকৃত রাখা যায়।
Template Method Pattern এর কাঠামো (Structure)
Template Method Pattern সাধারণত নিচের উপাদানগুলো নিয়ে কাজ করে:
- Abstract Class: এটি মূল অ্যালগরিদমের কাঠামো তৈরি করে এবং কিছু অবজেক্টের কার্যকলাপের জন্য "template method" নির্ধারণ করে।
- Concrete Class: এটি Abstract class থেকে ইনহেরিট করে, এবং যেখানে প্রয়োজন, সেখানে ঐ নির্দিষ্ট ধাপগুলোর বাস্তবায়ন করা হয়।
- Template Method: এটি সেই মেথড যা পুরো অ্যালগরিদমের কাঠামো তৈরি করে, কিন্তু কিছু অংশের বাস্তবায়ন subclasses এর উপর নির্ভর করে।
Template Method Pattern এর উদাহরণ
ধরা যাক, আমাদের একটি রান্নার প্রক্রিয়া (Cooking Process) আছে। রান্না করার একটি নির্দিষ্ট কাঠামো রয়েছে, যেমন প্রথমে উপকরণ প্রস্তুত করা, তারপর রান্না করা, এবং শেষে প্লেটিং করা। কিন্তু বিভিন্ন রান্নার জন্য কিছু ধাপ পরিবর্তিত হতে পারে (যেমন, তাপমাত্রা বা রান্নার সময়)। এই কারণে, আমরা Template Method Pattern ব্যবহার করতে পারি।
1. Abstract Class (CookingProcess)
abstract class CookingProcess {
// Template method
public final void cook() {
prepareIngredients();
cookDish();
plateDish();
serve();
}
// Steps to be implemented by subclasses
protected abstract void prepareIngredients();
protected abstract void cookDish();
protected abstract void plateDish();
// Common step for all
private void serve() {
System.out.println("Dish is ready to be served!");
}
}
2. Concrete Classes (VegetarianCooking, NonVegetarianCooking)
class VegetarianCooking extends CookingProcess {
@Override
protected void prepareIngredients() {
System.out.println("Preparing vegetables and spices...");
}
@Override
protected void cookDish() {
System.out.println("Cooking vegetarian dish...");
}
@Override
protected void plateDish() {
System.out.println("Plating the vegetarian dish...");
}
}
class NonVegetarianCooking extends CookingProcess {
@Override
protected void prepareIngredients() {
System.out.println("Preparing meat and spices...");
}
@Override
protected void cookDish() {
System.out.println("Cooking non-vegetarian dish...");
}
@Override
protected void plateDish() {
System.out.println("Plating the non-vegetarian dish...");
}
}
3. Client Code (Main)
public class TemplateMethodPatternExample {
public static void main(String[] args) {
CookingProcess vegetarianDish = new VegetarianCooking();
vegetarianDish.cook(); // Follow the template method to cook vegetarian dish
System.out.println("\n");
CookingProcess nonVegetarianDish = new NonVegetarianCooking();
nonVegetarianDish.cook(); // Follow the template method to cook non-vegetarian dish
}
}
Explanation:
- Abstract Class:
CookingProcessক্লাসটি মূল অ্যালগরিদমের কাঠামো নির্ধারণ করে (মেথডcook()), কিন্তু কিছু ধাপগুলি (যেমনprepareIngredients(),cookDish(), এবংplateDish())abstractমেথড হিসাবে ডিফাইন করা হয়, যা subclasses দ্বারা বাস্তবায়িত হবে। - Concrete Classes:
VegetarianCookingএবংNonVegetarianCookingক্লাসগুলিCookingProcessথেকে ইনহেরিট করে এবং তাদের নিজস্বভাবে বিশেষ ধাপগুলির বাস্তবায়ন করে (যেমন, উপকরণ প্রস্তুত করা, রান্না করা, প্লেটিং করা)। - Template Method:
cook()মেথডটি Template Method, যা মূল অ্যালগরিদমের কাঠামো তৈরি করে এবং ধাপগুলির জন্য সাবক্লাসে নির্দিষ্ট বাস্তবায়নকে কল করে।
Template Method Pattern এর সুবিধা
- Code Reusability: Template Method Pattern কোড পুনঃব্যবহারের সুবিধা দেয়, কারণ মূল কাঠামো একটি জায়গায় সংরক্ষিত থাকে এবং কেবলমাত্র কিছু অংশ পরিবর্তিত হয়।
- Control Flow: এটি কাজের মূল কন্ট্রোল প্রদান করে, কারণ আপনি শুধুমাত্র কিছু ধাপ কাস্টমাইজ করতে পারেন, তবে পুরো প্রক্রিয়া সুপারক্লাসে পরিচালিত হয়।
- Flexibility: এটি সিস্টেমের মধ্যে নতুন কাস্টম ধাপ বা আচরণ যুক্ত করার জন্য নমনীয়তা প্রদান করে।
Template Method Pattern এর সময় এবং স্থান জটিলতা
- Time Complexity: O(1), কারণ Template Method Pattern নির্দিষ্ট ধাপের তালিকা তৈরি করে, এবং এই ধাপগুলির মধ্যে কোনো পুনরাবৃত্তি বা অতিরিক্ত কার্যকলাপ নেই।
- Space Complexity: O(1), কারণ এটি কোনো অতিরিক্ত ডাটা স্ট্রাকচার বা মেমরি ব্যবহার করে না, শুধুমাত্র কার্যকলাপের ধাপগুলির জন্য রেফারেন্স রাখা হয়।
Template Method Pattern একটি শক্তিশালী behavioral design pattern যা অ্যাবস্ট্রাক্ট ক্লাসে একটি "template" মেথড নির্ধারণ করে এবং সেই মেথডের মধ্যে কিছু অংশ কাস্টমাইজড সাবক্লাসগুলির মাধ্যমে পূর্ণ করা হয়। এটি কোডের পুনঃব্যবহারযোগ্যতা, ফ্লেক্সিবিলিটি এবং কার্যকরী নিয়ন্ত্রণ প্রদান করে। এই প্যাটার্নটি workflow বা algorithmic process গুলিতে যেখানে কিছু স্টেপ স্থির থাকে এবং কিছু স্টেপ কাস্টমাইজ করা প্রয়োজন, সেখানে অত্যন্ত কার্যকরী।
Visitor Pattern একটি Behavioral Design Pattern যা অবজেক্টের স্ট্রাকচারের বাইরে থাকা কিছু নতুন কার্যকলাপ সংজ্ঞায়িত করতে ব্যবহৃত হয়। এই প্যাটার্নটি বিশেষভাবে উপকারী যখন আপনি একটি অবজেক্ট গঠন বা স্ট্রাকচার পরিবর্তন না করে, সেই স্ট্রাকচারের উপর বিভিন্ন অপারেশন প্রয়োগ করতে চান।
Visitor Pattern এ, আপনি একটি Visitor ক্লাস তৈরি করেন যা কিছু অবজেক্টের উপর অপারেশন বা কর্ম চালায়। এর মাধ্যমে আপনি বিভিন্ন ধরনের অপারেশন (যেমন গণনা, বৈধতা পরীক্ষা, প্রিন্ট) করতে পারেন, যেখানে অবজেক্টের ক্লাস কনক্রিট থাকলেও স্ট্রাকচারের পরিবর্তন ছাড়াই নতুন নতুন ফাংশনালিটি যোগ করা যায়।
Visitor Pattern এর উপকারিতা:
- নতুন অপারেশন যোগ করা সহজ: আপনি যখনই নতুন কোনও অপারেশন করতে চান, তখন আপনি কেবল একটি নতুন ভিজিটার ক্লাস তৈরি করতে পারেন, পুরনো কোডে কোন পরিবর্তন না এনে।
- স্ট্রাকচারে পরিবর্তন না করা: Visitor প্যাটার্ন আপনাকে অবজেক্টের স্ট্রাকচার পরিবর্তন না করেই নতুন ফাংশনালিটি বা অপারেশন প্রদান করতে দেয়।
- একটি কেন্দ্রীয় স্থান থেকে একাধিক অপারেশন চালানো: এই প্যাটার্নটি আপনাকে সমস্ত অবজেক্টের উপর একযোগে অপারেশন চালানোর সুবিধা দেয়।
Visitor Pattern এর কাঠামো
Visitor Pattern এর মধ্যে সাধারণত ৩টি গুরুত্বপূর্ণ উপাদান থাকে:
- Visitor Interface: এটি একটি ইন্টারফেস যা একটি visit মেথড নিয়ে থাকে এবং বিভিন্ন Element অবজেক্টে প্রয়োগ করার জন্য ডিজাইন করা হয়।
- Concrete Visitor: এটি
Visitorইন্টারফেসের কনক্রিট ইমপ্লিমেন্টেশন যেখানে কার্যকরী লজিক থাকে। - Element Interface: এটি একটি ইন্টারফেস যা
accept()মেথড ঘোষণা করে। Element অবজেক্টে ভিজিটরের visit মেথড কল করা হয়। - Concrete Element: এটি Element ইন্টারফেসের কনক্রিট ক্লাস, যা accept() মেথডের মাধ্যমে ভিজিটরকে অনুমতি দেয়।
Visitor Pattern এর উদাহরণ (Java)
ধরা যাক, আমাদের একটি কোর্স সিস্টেম রয়েছে যেখানে বিভিন্ন ধরনের কোর্স আছে (যেমন, MathematicsCourse, ScienceCourse), এবং আমাদের প্রত্যেকটি কোর্সের জন্য Discount এবং Certificate তৈরি করতে হবে। আমরা Visitor Pattern ব্যবহার করে এই সমস্যা সমাধান করব।
Step 1: Visitor Interface
interface CourseVisitor {
void visit(MathematicsCourse mathCourse);
void visit(ScienceCourse scienceCourse);
}
Step 2: Concrete Visitor Classes
class DiscountVisitor implements CourseVisitor {
@Override
public void visit(MathematicsCourse mathCourse) {
System.out.println("Applying discount on Mathematics course");
// Implement discount logic for Mathematics course
}
@Override
public void visit(ScienceCourse scienceCourse) {
System.out.println("Applying discount on Science course");
// Implement discount logic for Science course
}
}
class CertificateVisitor implements CourseVisitor {
@Override
public void visit(MathematicsCourse mathCourse) {
System.out.println("Issuing certificate for Mathematics course");
// Implement certificate issuing logic for Mathematics course
}
@Override
public void visit(ScienceCourse scienceCourse) {
System.out.println("Issuing certificate for Science course");
// Implement certificate issuing logic for Science course
}
}
Step 3: Element Interface
interface Course {
void accept(CourseVisitor visitor);
}
Step 4: Concrete Element Classes
class MathematicsCourse implements Course {
@Override
public void accept(CourseVisitor visitor) {
visitor.visit(this);
}
}
class ScienceCourse implements Course {
@Override
public void accept(CourseVisitor visitor) {
visitor.visit(this);
}
}
Step 5: Client Code
public class VisitorPatternExample {
public static void main(String[] args) {
// Create concrete courses
Course mathCourse = new MathematicsCourse();
Course scienceCourse = new ScienceCourse();
// Create visitors
CourseVisitor discountVisitor = new DiscountVisitor();
CourseVisitor certificateVisitor = new CertificateVisitor();
// Applying visitors to courses
mathCourse.accept(discountVisitor); // Discount on Mathematics
scienceCourse.accept(discountVisitor); // Discount on Science
mathCourse.accept(certificateVisitor); // Certificate for Mathematics
scienceCourse.accept(certificateVisitor); // Certificate for Science
}
}
ব্যাখ্যা:
- CourseVisitor: এটি একটি ইন্টারফেস যা
visit()মেথড ধারণ করে। এই মেথডগুলি বিভিন্ন কোর্স (যেমন MathematicsCourse, ScienceCourse) এর জন্য কার্যকরী হবে। - ConcreteVisitor: এখানে দুটি কনক্রিট ভিজিটর রয়েছে, একটি DiscountVisitor এবং একটি CertificateVisitor, যা কোর্সের উপর Discount এবং Certificate প্রয়োগ করে।
- Course: এটি একটি ইন্টারফেস যা
accept()মেথড ধারণ করে, যাতে প্রতিটি কোর্স ক্লাস (যেমন MathematicsCourse, ScienceCourse) ভিজিটরেরvisit()মেথডকে কল করে। - ConcreteElement: MathematicsCourse এবং ScienceCourse ক্লাস দুটি accept() মেথড ইমপ্লিমেন্ট করে, যেখানে তারা ভিজিটরের
visit()মেথডে নিজেকে পাঠায়।
আউটপুট:
Applying discount on Mathematics course
Applying discount on Science course
Issuing certificate for Mathematics course
Issuing certificate for Science course
Visitor Pattern এর সুবিধা এবং ব্যবহার
সুবিধা:
- নতুন অপারেশন যোগ করা সহজ: নতুন নতুন কার্যকলাপ (operation) যুক্ত করা খুব সহজ, আপনি কেবল নতুন ভিজিটর ক্লাস তৈরি করে তা প্রয়োগ করতে পারেন, কোর্সের ক্লাসে কোন পরিবর্তন না করেই।
- স্ট্রাকচারে পরিবর্তন ছাড়া ফাংশনালিটি যোগ: আপনি অবজেক্টের স্ট্রাকচারে কোনও পরিবর্তন না করেও নতুন নতুন ফাংশনালিটি বা অপারেশন যোগ করতে পারেন।
- কোড বিচ্ছিন্নতা: একাধিক ভিজিটর এবং অবজেক্টের মধ্যে কার্যকলাপের পৃথকীকরণ আপনার কোডের রক্ষণাবেক্ষণ এবং পরিবর্তন সহজ করে।
ব্যবহার:
- কমপ্লেক্স অবজেক্ট স্ট্রাকচার: যেখানে একাধিক অপারেশন অবজেক্টে প্রয়োগ করা হয়, কিন্তু অবজেক্টের স্ট্রাকচারে পরিবর্তন না করা হয়।
- কমপ্লেক্স রিপোর্টিং সিস্টেম: যেখানে আপনি বিভিন্ন ধরনের রিপোর্ট বা স্ট্যাটিস্টিকস তৈরি করতে চান, তবে রিপোর্টিং লজিক অবজেক্টের মধ্যে প্রতিস্থাপন না করেই প্রয়োগ করা সম্ভব।
- প্রসেসিং ডেটা: যেখানে বিভিন্ন ডেটার উপর বিভিন্ন ধরনের প্রসেসিং করা হয় (যেমন, discount, billing, validation)।
সারাংশ
Visitor Pattern একটি Behavioral Design Pattern যা অবজেক্টের উপর বিভিন্ন অপারেশন (যেমন, Discount, Certificate) প্রয়োগ করতে সাহায্য করে, অবজেক্ট স্ট্রাকচারের পরিবর্তন না করে। এটি একটি open/close principle অনুসরণ করে, যেখানে নতুন অপারেশন বা কার্যকলাপ সংযোজন করা যায় কিন্তু বিদ্যমান কোডে কোনও পরিবর্তন করতে হয় না। Java তে Visitor Pattern বাস্তবায়ন করে একাধিক অপারেশন খুবই কার্যকরভাবে প্রয়োগ করা যায়, বিশেষ করে যদি সেই অপারেশন গুলি অনেক অবজেক্টে প্রয়োগ করতে হয়।
Read more