জাভাতে ডিজাইন প্যাটার্নস (Design Patterns) হল সেই সমাধান যা সাধারণ সমস্যার পুনরাবৃত্তি সমাধান করতে ব্যবহৃত হয়। বিভিন্ন ডিজাইন প্যাটার্নস সিস্টেমের কাঠামো এবং সম্পর্ক নির্ধারণে সাহায্য করে। এখানে কিছু সাধারণ ডিজাইন প্যাটার্নের উদাহরণ দেওয়া হলো:
Singleton Pattern নিশ্চিত করে যে একটি ক্লাসের শুধুমাত্র একটি ইনস্ট্যান্স থাকবে এবং তা গ্লোবাল অ্যাক্সেস পাবে।
public class Singleton {
// একটি স্ট্যাটিক ভেরিয়েবল যেখানে ক্লাসের একমাত্র ইনস্ট্যান্স রাখা হবে
private static Singleton instance;
// কনস্ট্রাক্টর প্রাইভেট করতে হবে যাতে বাইরের কোড নতুন ইনস্ট্যান্স তৈরি করতে না পারে
private Singleton() {}
// একটি পাবলিক মেথড যা ক্লাসের একমাত্র ইনস্ট্যান্স রিটার্ন করবে
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
public void showMessage() {
System.out.println("Hello from Singleton!");
}
public static void main(String[] args) {
Singleton singleton = Singleton.getInstance();
singleton.showMessage();
}
}
ব্যাখ্যা:
এখানে Singleton
ক্লাসটি নিশ্চিত করে যে এটি থেকে কেবলমাত্র একটি ইনস্ট্যান্স তৈরি হবে এবং সেই ইনস্ট্যান্সটি গ্লোবাল অ্যাক্সেসযোগ্য হবে।
Factory Pattern একটি প্যাটার্ন যেখানে অবজেক্ট তৈরি করার জন্য একটি আলাদা ক্লাস বা মেথড ব্যবহার করা হয়। এটি অবজেক্ট তৈরির প্রক্রিয়াটি ক্লাসের বাইরে রেখে ডায়নামিকভাবে কনফিগার করা যায়।
// ইন্টারফেস
interface Animal {
void sound();
}
// Concrete Classes
class Dog implements Animal {
public void sound() {
System.out.println("Dog barks");
}
}
class Cat implements Animal {
public void sound() {
System.out.println("Cat meows");
}
}
// Factory Class
class AnimalFactory {
public static Animal getAnimal(String animalType) {
if (animalType == null) {
return null;
}
if (animalType.equalsIgnoreCase("Dog")) {
return new Dog();
} else if (animalType.equalsIgnoreCase("Cat")) {
return new Cat();
}
return null;
}
}
public class FactoryPatternExample {
public static void main(String[] args) {
Animal dog = AnimalFactory.getAnimal("Dog");
dog.sound();
Animal cat = AnimalFactory.getAnimal("Cat");
cat.sound();
}
}
ব্যাখ্যা:
এখানে AnimalFactory
ক্লাসের মাধ্যমে আমরা আলাদা আলাদা প্রাণী (Dog
, Cat
) তৈরি করি, যা আমাদের কোডে অবজেক্ট তৈরি করার প্রক্রিয়াটি সহজ করে দেয়।
Observer Pattern হল একটি আচরণগত ডিজাইন প্যাটার্ন যেখানে একটি সাবজেক্ট তার সকল অবজারভারকে অবহিত করে যদি কোনো পরিবর্তন ঘটে।
import java.util.ArrayList;
import java.util.List;
// Observer Interface
interface Observer {
void update(String message);
}
// Concrete Observer
class ConcreteObserver implements Observer {
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
public void update(String message) {
System.out.println(name + " received message: " + message);
}
}
// Subject Interface
interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// Concrete Subject
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String message;
public void setMessage(String message) {
this.message = message;
notifyObservers();
}
public void registerObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(message);
}
}
}
public class ObserverPatternExample {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver observer1 = new ConcreteObserver("Observer 1");
ConcreteObserver observer2 = new ConcreteObserver("Observer 2");
subject.registerObserver(observer1);
subject.registerObserver(observer2);
subject.setMessage("Hello Observers!");
}
}
ব্যাখ্যা:
এখানে ConcreteSubject
ক্লাসটি একটি মেসেজ সেট করে এবং তার সমস্ত অবজারভারকে অবহিত করে। Observer
ক্লাসটি তার নিজস্ব update
মেথডে পরিবর্তন সনাক্ত করে এবং মেসেজটি গ্রহণ করে।
Decorator Pattern একটি স্ট্রাকচারাল ডিজাইন প্যাটার্ন যা একটি অবজেক্টের আচরণ পরিবর্তন বা প্রসারিত করার জন্য ব্যবহৃত হয়, কিন্তু অবজেক্টের মৌলিক কনফিগারেশন পরিবর্তন না করে।
// Base interface
interface Coffee {
double cost();
}
// Concrete Class
class SimpleCoffee implements Coffee {
public double cost() {
return 5.0;
}
}
// Decorator Class
class MilkDecorator implements Coffee {
private Coffee coffee;
public MilkDecorator(Coffee coffee) {
this.coffee = coffee;
}
public double cost() {
return coffee.cost() + 1.0; // Adding cost of milk
}
}
class SugarDecorator implements Coffee {
private Coffee coffee;
public SugarDecorator(Coffee coffee) {
this.coffee = coffee;
}
public double cost() {
return coffee.cost() + 0.5; // Adding cost of sugar
}
}
public class DecoratorPatternExample {
public static void main(String[] args) {
Coffee coffee = new SimpleCoffee();
System.out.println("Cost of Simple Coffee: " + coffee.cost());
Coffee milkCoffee = new MilkDecorator(coffee);
System.out.println("Cost of Coffee with Milk: " + milkCoffee.cost());
Coffee milkSugarCoffee = new SugarDecorator(milkCoffee);
System.out.println("Cost of Coffee with Milk and Sugar: " + milkSugarCoffee.cost());
}
}
ব্যাখ্যা:
এখানে SimpleCoffee
ক্লাসের আচরণ প্রসারিত করার জন্য MilkDecorator
এবং SugarDecorator
ক্লাসগুলো ব্যবহার করা হয়েছে। এই প্যাটার্নটি আসল অবজেক্টের আচরণ পরিবর্তন না করে নতুন বৈশিষ্ট্য যোগ করে।
Strategy Pattern হল একটি আচরণগত ডিজাইন প্যাটার্ন যা একটি এলগরিদমকে একটি ক্লাসের পরিবর্তে আলাদা আলাদা ক্লাসে ইনক্লুড করে এবং এগুলোর মধ্যে পরিবর্তনযোগ্যতা আনে।
// 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 PaymentContext {
private PaymentStrategy strategy;
public PaymentContext(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void executePayment(int amount) {
strategy.pay(amount);
}
}
public class StrategyPatternExample {
public static void main(String[] args) {
PaymentContext context = new PaymentContext(new CreditCardPayment());
context.executePayment(100);
context = new PaymentContext(new PayPalPayment());
context.executePayment(200);
}
}
ব্যাখ্যা:
এখানে PaymentStrategy
ইন্টারফেসের মাধ্যমে বিভিন্ন পেমেন্ট পদ্ধতি (যেমন Credit Card, PayPal) পৃথকভাবে বাস্তবায়িত হয়েছে। PaymentContext
ক্লাসটি একে একে বিভিন্ন পেমেন্ট পদ্ধতি ব্যবহার করে পেমেন্ট সম্পাদন করে।
এই ডিজাইন প্যাটার্নগুলি আপনার কোডকে আরো উন্নত, রিইউজেবল এবং এক্সটেনসিবল করে তোলে।
Singleton Design Pattern একটি সৃজনশীল ডিজাইন প্যাটার্ন যা নিশ্চিত করে যে একটি ক্লাসের কেবলমাত্র একটি ইনস্ট্যান্স থাকবে এবং সেই ইনস্ট্যান্সটি অ্যাক্সেস করার জন্য একটি গেটার মেথড থাকবে। এটি সাধারণত ব্যবহৃত হয় যখন কোনো রিসোর্স বা ডেটা শেয়ার করতে হবে যা একাধিক থ্রেড বা অ্যাপ্লিকেশন অংশের মধ্যে শেয়ার করা হয়।
এখানে আমরা একটি Singleton Class তৈরি করব যা একটি কেবল একক ইনস্ট্যান্স প্রদান করবে এবং সেটি ব্যবহার করবে।
public class Singleton {
// Singleton ক্লাসের একমাত্র ইনস্ট্যান্স
private static Singleton instance;
// কনস্ট্রাক্টরকে প্রাইভেট করা হয়েছে যাতে বাইরের কোড এটি ইনস্ট্যান্স করতে না পারে
private Singleton() {
// কিছু Initialization কোড
}
// গেটার মেথড যা ক্লাসের একমাত্র ইনস্ট্যান্স প্রদান করে
public static Singleton getInstance() {
// ইনস্ট্যান্স তৈরি করা হবে যদি এটি null থাকে
if (instance == null) {
// Synchronization ব্লক ব্যবহার করা হয়েছে যাতে থ্রেড সেফ থাকে
synchronized (Singleton.class) {
// আবার চেক করা হবে যাতে একাধিক থ্রেড একই সময় ইনস্ট্যান্স তৈরি না করে
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
// Singleton ক্লাসের কিছু ফাংশন
public void showMessage() {
System.out.println("Hello from Singleton!");
}
}
public class SingletonPatternTest {
public static void main(String[] args) {
// Singleton ইনস্ট্যান্স অ্যাক্সেস করা
Singleton singleton = Singleton.getInstance();
singleton.showMessage(); // "Hello from Singleton!" মেসেজ প্রদর্শন
// একই ইনস্ট্যান্স পুনরায় ব্যবহার
Singleton anotherSingleton = Singleton.getInstance();
anotherSingleton.showMessage();
// নিশ্চিত করা যে দুটি রেফারেন্স একই ইনস্ট্যান্স পয়েন্ট করছে
System.out.println(singleton == anotherSingleton); // true
}
}
Singleton
ক্লাসের কনস্ট্রাক্টরকে private
করা হয়েছে, যাতে বাইরের কোড এ ক্লাসটির ইনস্ট্যান্স তৈরি না করতে পারে। এটি Singleton প্যাটার্নের একটি মূল বৈশিষ্ট্য।private static Singleton instance;
এই স্ট্যাটিক ভেরিয়েবলটি ক্লাসের একমাত্র ইনস্ট্যান্স হিসেবে কাজ করবে। প্রথমবার যখন getInstance()
মেথডটি কল করা হবে, তখন ইনস্ট্যান্স তৈরি হবে।synchronized
ব্লক ব্যবহার করা হয়েছে যাতে এটি থ্রেড সেফ হয়, অর্থাৎ একাধিক থ্রেড একই সময়ে একে তৈরি করতে না পারে। তবে, এখানে দুইটি if
চেক করা হয়েছে যাতে একাধিক থ্রেড প্রথমে ইনস্ট্যান্স তৈরি করতে চেষ্টা করলে তা প্রতিরোধ করা যায়।showMessage()
একটি সাধারণ মেথড যা এই Singleton ক্লাসের একটি ফাংশনালিটি প্রদর্শন করে।SingletonPatternTest
ক্লাসের মধ্যে, getInstance()
মেথড ব্যবহার করে Singleton ক্লাসের ইনস্ট্যান্স এক্সেস করা হয়। আমরা দুটি আলাদা ভেরিয়েবল দিয়ে একই ইনস্ট্যান্স এক্সেস করেছি এবং তাদের সমতা যাচাই করেছি। এই চেকের ফলস্বরূপ true
হবে, যা নিশ্চিত করে যে এই দুটি ভেরিয়েবল একই ইনস্ট্যান্স পয়েন্ট করছে।Singleton
ক্লাস তৈরি করতে আমরা প্রথমে instance
ভেরিয়েবলটি চেক করি যদি এটি null
না হয়, তারপর synchronized
ব্লক ব্যবহার করি যাতে একাধিক থ্রেড একই সময় ইনস্ট্যান্স তৈরি করতে না পারে।এই উদাহরণটি দেখায় কিভাবে Singleton Design Pattern বাস্তবায়িত করা যায়। Singleton প্যাটার্নের মাধ্যমে আপনি নিশ্চিত করতে পারেন যে একটি ক্লাসের শুধুমাত্র এক ইনস্ট্যান্স থাকবে, যা অন্যান্য অংশের মধ্যে শেয়ার করা যাবে।
Factory Design Pattern একটি ক্রিয়েশনাল প্যাটার্ন যা একটি ক্লাসের দায়িত্ব দেয় নির্দিষ্ট টাইপের অবজেক্ট তৈরি করার জন্য। এটি বিশেষত ব্যবহার করা হয় যখন অবজেক্ট তৈরি করার পদ্ধতি বা প্রক্রিয়া জটিল হয় বা পরিবর্তনশীল হয়, এবং আপনি একাধিক ধরণের অবজেক্ট তৈরি করতে চান একই ইন্টারফেস বা সুপারক্লাস ব্যবহার করে।
এই প্যাটার্নের প্রধান সুবিধা হল, অবজেক্ট তৈরি করার প্রক্রিয়াটি ক্লায়েন্ট কোড থেকে আড়াল করা হয়, এবং ক্লায়েন্ট কেবলমাত্র ফ্যাক্টরি ক্লাসের মাধ্যমে অবজেক্ট তৈরি করে।
ধরা যাক, আমরা একটি কার ফ্যাক্টরি তৈরি করতে যাচ্ছি যেখানে বিভিন্ন ধরণের গাড়ি তৈরি হবে (যেমন, Sedan
, SUV
, Truck
), এবং আমাদের প্রয়োজন একটি ফ্যাক্টরি প্যাটার্ন যা নির্দিষ্ট গাড়ি টাইপ অনুযায়ী অবজেক্ট তৈরি করবে।
প্রথমে আমরা একটি Car
ইন্টারফেস তৈরি করি যেটি গাড়ির জন্য মৌলিক ফাংশনালিটি সংজ্ঞায়িত করবে।
// Car ইন্টারফেস
public interface Car {
void drive();
}
এখন আমরা Car
ইন্টারফেস ইমপ্লিমেন্ট করে কিছু নির্দিষ্ট গাড়ি ক্লাস তৈরি করি।
// Sedan গাড়ি
public class Sedan implements Car {
@Override
public void drive() {
System.out.println("Driving a Sedan!");
}
}
// SUV গাড়ি
public class SUV implements Car {
@Override
public void drive() {
System.out.println("Driving an SUV!");
}
}
// Truck গাড়ি
public class Truck implements Car {
@Override
public void drive() {
System.out.println("Driving a Truck!");
}
}
এখন একটি ফ্যাক্টরি ক্লাস তৈরি করি যা বিভিন্ন গাড়ির অবজেক্ট তৈরি করবে।
// CarFactory ক্লাস
public class CarFactory {
// ফ্যাক্টরি মেথড যা নির্দিষ্ট গাড়ি টাইপ অনুযায়ী অবজেক্ট তৈরি করবে
public static Car getCar(String carType) {
if (carType == null) {
return null;
}
if (carType.equalsIgnoreCase("Sedan")) {
return new Sedan();
} else if (carType.equalsIgnoreCase("SUV")) {
return new SUV();
} else if (carType.equalsIgnoreCase("Truck")) {
return new Truck();
}
return null;
}
}
এখন ক্লায়েন্ট কোডে ফ্যাক্টরি ব্যবহার করে গাড়ির অবজেক্ট তৈরি করা হবে এবং তাদের drive()
মেথড কল করা হবে।
// Main ক্লাস (Client Code)
public class Main {
public static void main(String[] args) {
// Sedan তৈরি
Car sedan = CarFactory.getCar("Sedan");
sedan.drive(); // Output: Driving a Sedan!
// SUV তৈরি
Car suv = CarFactory.getCar("SUV");
suv.drive(); // Output: Driving an SUV!
// Truck তৈরি
Car truck = CarFactory.getCar("Truck");
truck.drive(); // Output: Driving a Truck!
}
}
Car
ইন্টারফেস তৈরি করা হয়েছে যা একটি drive()
মেথড ডিক্লেয়ার করেছে। এটি সমস্ত ধরনের গাড়ির জন্য কমন ফাংশনালিটি প্রদান করবে।Sedan
, SUV
, এবং Truck
ক্লাসগুলি Car
ইন্টারফেসের মাধ্যমে বাস্তবায়িত হয়েছে। প্রতিটি ক্লাসের মধ্যে তাদের নিজস্ব drive()
মেথড রয়েছে যা তাদের নিজস্ব বাস্তবায়ন করে।CarFactory
একটি ফ্যাক্টরি ক্লাস যা একটি স্ট্যাটিক মেথড getCar()
প্রদান করে। এটি গাড়ির ধরন অনুযায়ী উপযুক্ত ক্লাসের অবজেক্ট তৈরি করে।Main
ক্লাসে, আমরা CarFactory.getCar()
মেথডের মাধ্যমে বিভিন্ন ধরনের গাড়ির অবজেক্ট তৈরি করেছি এবং তাদের drive()
মেথড কল করেছি।ফ্যাক্টরি ডিজাইন প্যাটার্ন একটি খুবই কার্যকর প্যাটার্ন যা অবজেক্ট তৈরির প্রক্রিয়া সহজ করে এবং কোডের পুনঃব্যবহারযোগ্যতা ও মেইন্টেনেবিলিটি বাড়ায়। এটি বিভিন্ন পরিস্থিতিতে ব্যবহার করা যেতে পারে যেখানে অবজেক্ট তৈরি করা একটি জটিল প্রক্রিয়া হতে পারে।
Observer Design Pattern হল একটি আচরণগত ডিজাইন প্যাটার্ন যা একাধিক অবজার্ভার (subscriber) কে একটি বিষয় (subject) এর পরিবর্তন সম্পর্কে অবহিত করতে ব্যবহৃত হয়। এটি ইভেন্ট হ্যান্ডলিং বা ডাটা আপডেটের ক্ষেত্রে খুবই কার্যকর, বিশেষত যখন একাধিক অবজার্ভার থাকে যারা একত্রে একটি বিষয় (subject) এর অবস্থা পরিবর্তনের উপর নজর রাখে।
নিচে Observer Pattern ব্যবহার করে ইভেন্ট হ্যান্ডলিংয়ের একটি উদাহরণ দেওয়া হয়েছে যেখানে একটি Subject
ক্লাস তার অবজার্ভারদের খবর দেয় যখন তার স্টেট পরিবর্তন হয়।
import java.util.ArrayList;
import java.util.List;
// Observer Interface
interface Observer {
void update(String message);
}
// Concrete Observer - এটি Observer Interface ইমপ্লিমেন্ট করে
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: " + message);
}
}
// Subject (Publisher) Interface
interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// Concrete Subject - এটি Subject Interface ইমপ্লিমেন্ট করে
class ConcreteSubject implements Subject {
private List<Observer> observers = new ArrayList<>();
private String state;
public void setState(String state) {
this.state = state;
notifyObservers();
}
public String getState() {
return state;
}
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(state);
}
}
}
// Main Class to demonstrate Observer Pattern
public class ObserverPatternExample {
public static void main(String[] args) {
// ConcreteSubject তৈরি
ConcreteSubject subject = new ConcreteSubject();
// ConcreteObservers তৈরি
Observer observer1 = new ConcreteObserver("Observer 1");
Observer observer2 = new ConcreteObserver("Observer 2");
Observer observer3 = new ConcreteObserver("Observer 3");
// Observer গুলো সাবস্ক্রাইব করে Subject এ
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.addObserver(observer3);
// Subject এর state পরিবর্তন করলে সকল Observerদের খবর দেওয়া হবে
System.out.println("State change 1: ");
subject.setState("New State: 1");
// Observer 1 কে সরিয়ে দেয়া
subject.removeObserver(observer1);
// আবার state change
System.out.println("\nState change 2: ");
subject.setState("New State: 2");
}
}
update()
মেথডের মাধ্যমে অবজার্ভারদের অবহিত করবে।Observer
ইন্টারফেস ইমপ্লিমেন্ট করে এবং update()
মেথডের মাধ্যমে একটি বার্তা গ্রহণ করে তা প্রদর্শন করে।addObserver()
, removeObserver()
, এবং notifyObservers()
মেথড প্রদান করে। এটি অবজার্ভারদের যুক্ত করার, তাদের সরিয়ে দেওয়ার, এবং তাদের সবকে অবহিত করার কাজ করে।Subject
ইন্টারফেস ইমপ্লিমেন্ট করে এবং তার state
এর পরিবর্তন ঘটানোর সাথে সাথে অবজার্ভারদের অবহিত করে। setState()
মেথডের মাধ্যমে স্টেট পরিবর্তন করা হয় এবং notifyObservers()
এর মাধ্যমে সকল অবজার্ভারকে অবহিত করা হয়।ObserverPatternExample
ক্লাসে একটি ConcreteSubject
এবং তিনটি ConcreteObserver
তৈরি করা হয়। আমরা প্রথমে সকল অবজার্ভারকে সাবস্ক্রাইব করে দিয়ে স্টেট পরিবর্তন ঘটাই, পরে একটি অবজার্ভার সরিয়ে দিয়ে আবার স্টেট পরিবর্তন করি।State change 1:
Observer 1 received message: New State: 1
Observer 2 received message: New State: 1
Observer 3 received message: New State: 1
State change 2:
Observer 2 received message: New State: 2
Observer 3 received message: New State: 2
Subject
এর স্টেট পরিবর্তন হলে, সকল অবজার্ভারদের অবহিত করা হয়।addObserver()
এবং removeObserver()
মেথডের মাধ্যমে সহজেই যুক্ত বা সরিয়ে ফেলতে পারেন।এটি মূলত GUI অ্যাপ্লিকেশন, ইভেন্ট হ্যান্ডলিং, এবং ডাটা মডেল আপডেটের জন্য ব্যবহৃত হয়।
Decorator Design Pattern একটি স্ট্রাকচারাল ডিজাইন প্যাটার্ন, যা একটি অবজেক্টের আচরণ বা ফাংশনালিটি ডাইনামিকভাবে পরিবর্তন করার জন্য ব্যবহৃত হয়। এটি নতুন ক্লাস তৈরি না করে, একটি অবজেক্টের আচরণকে ডেকোরেটর অবজেক্টের মাধ্যমে কাস্টমাইজ বা প্রসারিত করতে সাহায্য করে।
নিচে একটি উদাহরণ দেওয়া হলো, যেখানে Decorator Pattern ব্যবহার করে একটি অবজেক্টের ফাংশনালিটি ডাইনামিকভাবে পরিবর্তন করা হয়েছে:
প্রথমে একটি বেস ক্লাস তৈরি করা হচ্ছে, যেটি একটি সাধারণ ফাংশনালিটি প্রদর্শন করবে।
// Component Interface
public interface Coffee {
double cost();
}
এটি Coffee
ইন্টারফেসের একটি কনক্রিট (Concrete) বাস্তবায়ন যা একটি সাধারণ কফি ক্লাস তৈরি করবে।
// Concrete Component
public class SimpleCoffee implements Coffee {
@Override
public double cost() {
return 5.0; // সাধারণ কফির দাম
}
}
এটি Coffee
ইন্টারফেসকে ইমপ্লিমেন্ট করবে এবং অন্যান্য ডেকোরেটরের জন্য বেস ক্লাস হিসেবে কাজ করবে।
// Decorator Class
public abstract class CoffeeDecorator implements Coffee {
protected Coffee decoratedCoffee;
public CoffeeDecorator(Coffee coffee) {
this.decoratedCoffee = coffee;
}
@Override
public double cost() {
return decoratedCoffee.cost();
}
}
এখন বিভিন্ন ডেকোরেটর ক্লাস তৈরি করা হবে, যেগুলি কফির মূল অবজেক্টের আচরণ পরিবর্তন করবে।
// Concrete Decorator 1: Milk
public class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return super.cost() + 1.5; // দুধ যোগ করলে দাম বৃদ্ধি
}
}
// Concrete Decorator 2: Sugar
public class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee);
}
@Override
public double cost() {
return super.cost() + 0.5; // চিনি যোগ করলে দাম বৃদ্ধি
}
}
এখানে কিভাবে ডেকোরেটর প্যাটার্ন ব্যবহার করে কফির ফাংশনালিটি পরিবর্তন করা হবে তা দেখানো হয়েছে।
public class DecoratorPatternExample {
public static void main(String[] args) {
// সাধারণ কফি তৈরি
Coffee simpleCoffee = new SimpleCoffee();
System.out.println("Simple Coffee cost: " + simpleCoffee.cost());
// দুধসহ কফি তৈরি
Coffee milkCoffee = new MilkDecorator(new SimpleCoffee());
System.out.println("Milk Coffee cost: " + milkCoffee.cost());
// দুধ এবং চিনি সহ কফি তৈরি
Coffee milkSugarCoffee = new SugarDecorator(new MilkDecorator(new SimpleCoffee()));
System.out.println("Milk and Sugar Coffee cost: " + milkSugarCoffee.cost());
}
}
Simple Coffee cost: 5.0
Milk Coffee cost: 6.5
Milk and Sugar Coffee cost: 7.0
Coffee
): এটি একটি সাধারণ ইন্টারফেস যা সমস্ত কফি ক্লাসের জন্য নির্দিষ্ট আচরণ ঘোষণা করে। এখানে cost()
মেথডের মাধ্যমে কফির দাম পাওয়া যায়।SimpleCoffee
): এটি Coffee
ইন্টারফেসের বাস্তবায়ন এবং একটি সাধারণ কফির দাম প্রদান করে।CoffeeDecorator
): এটি Coffee
ইন্টারফেসে ডেকোরেটরের বেস ক্লাস হিসেবে কাজ করে এবং অন্যান্য ডেকোরেটর ক্লাসে শেয়ার করা ফাংশনালিটি ধারণ করে। cost()
মেথডটি ডেকোরেটরের ভিতরে ডেকোরেটেড অবজেক্টের cost()
মেথডে কল করা হয়।MilkDecorator
, SugarDecorator
): এগুলি CoffeeDecorator
ক্লাসের সাবক্লাস এবং কফির মূল অবজেক্টের আচরণ পরিবর্তন করতে নির্দিষ্ট ফাংশনালিটি যোগ করে (যেমন, দুধ এবং চিনি যোগ করা)।BufferedReader
, FileReader
ইত্যাদিতে ডেকোরেটর প্যাটার্ন ব্যবহার করা হয় যেখানে একাধিক স্ট্রিমের উপর বিভিন্ন ফিল্টার প্রয়োগ করা হয়।এটি একটি খুব শক্তিশালী ডিজাইন প্যাটার্ন যা ফ্লেক্সিবিলিটি প্রদান করে এবং অবজেক্টের আচরণ পরিবর্তন বা প্রসারিত করার জন্য নতুন কোডের প্রয়োজনীয়তা কমায়।
Strategy Design Pattern হল একটি behavioral design pattern যা একটি এলগরিদমের পরিবারকে ডিফাইন করে এবং তাদের একটি ইন্টারফেসের মাধ্যমে সিলেক্ট করতে সক্ষম করে। এটি runtime এ এলগরিদম পরিবর্তন করতে সাহায্য করে এবং ক্লাসের মধ্যে এলগরিদমের উপযুক্ত ব্যবহার করা সম্ভব করে।
Strategy Pattern-এর মূল ধারণা হল, ক্লাসের মধ্যে আলাদা আলাদা এলগরিদম সংরক্ষণ করা এবং সেগুলি প্রয়োজনে runtime এ ব্যবহার করা। এই প্যাটার্নের মাধ্যমে, কোডের মধ্যে কোন hard-coded এলগরিদম বা লজিক থাকেনা এবং এটি আরও ফ্লেক্সিবল ও পরিবর্তনযোগ্য হয়ে ওঠে।
ধরা যাক আমাদের একটি সফটওয়্যার সিস্টেম আছে যেখানে কিছু কনটেক্সটে ভিন্ন ভিন্ন এলগরিদম প্রয়োগ করা হয় (যেমন বিভিন্ন ক্যালকুলেশন বা ডিস্কাউন্ট ক্যালকুলেশন)। এখানে, Strategy Design Pattern ব্যবহার করা হবে।
প্রথমে, আমরা একটি Strategy
ইন্টারফেস তৈরি করবো যা বিভিন্ন এলগরিদমের জন্য কমন API ডিফাইন করবে।
public interface PaymentStrategy {
void pay(int amount);
}
এবার আমরা PaymentStrategy
ইন্টারফেসের মাধ্যমে বিভিন্ন এলগরিদম তৈরি করবো। যেমন, CreditCardPayment
এবং PayPalPayment
।
// Credit Card Payment Strategy
public class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
public CreditCardPayment(String cardNumber) {
this.cardNumber = cardNumber;
}
@Override
public void pay(int amount) {
System.out.println("Paid " + amount + " using Credit Card: " + cardNumber);
}
}
// PayPal Payment Strategy
public class PayPalPayment implements PaymentStrategy {
private String email;
public PayPalPayment(String email) {
this.email = email;
}
@Override
public void pay(int amount) {
System.out.println("Paid " + amount + " using PayPal with email: " + email);
}
}
এখন আমরা একটি PaymentContext
ক্লাস তৈরি করবো যা কোন পেমেন্ট স্ট্র্যাটেজি ব্যবহার করবে তা নির্বাচন করবে। এটি run-time এ পরিবর্তনশীল স্ট্র্যাটেজি ব্যবহার করতে পারে।
public class PaymentContext {
private PaymentStrategy paymentStrategy;
// পেমেন্ট স্ট্র্যাটেজি সেট করা
public PaymentContext(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
// পেমেন্ট পদ্ধতি ব্যবহার করা
public void executePayment(int amount) {
paymentStrategy.pay(amount);
}
// স্ট্র্যাটেজি পরিবর্তন করা
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
}
এবার আমরা ক্লায়েন্ট কোড তৈরি করবো যা বিভিন্ন পেমেন্ট স্ট্র্যাটেজি ব্যবহার করবে।
public class StrategyPatternExample {
public static void main(String[] args) {
// প্রথমে Credit Card পেমেন্ট স্ট্র্যাটেজি ব্যবহার করা হচ্ছে
PaymentStrategy creditCardPayment = new CreditCardPayment("1234-5678-9876-5432");
PaymentContext paymentContext = new PaymentContext(creditCardPayment);
paymentContext.executePayment(500);
// পেমেন্ট স্ট্র্যাটেজি পরিবর্তন করা হচ্ছে (PayPal)
PaymentStrategy payPalPayment = new PayPalPayment("user@example.com");
paymentContext.setPaymentStrategy(payPalPayment);
paymentContext.executePayment(300);
}
}
Paid 500 using Credit Card: 1234-5678-9876-5432
Paid 300 using PayPal with email: user@example.com
PaymentStrategy
):pay
মেথড ডিফাইন করে, যাতে বিভিন্ন ধরনের পেমেন্ট স্ট্র্যাটেজি এটির মাধ্যমে কাজ করতে পারে।CreditCardPayment
ও PayPalPayment
):PaymentStrategy
ইন্টারফেস ইমপ্লিমেন্ট করে এবং তাদের নিজস্ব পেমেন্ট এলগরিদম (ক্রেডিট কার্ড পেমেন্ট বা পেপ্যাল পেমেন্ট) বাস্তবায়ন করে।PaymentContext
):StrategyPatternExample
):PaymentContext
ব্যবহার করি এবং পেমেন্ট স্ট্র্যাটেজি পরিবর্তন করে আলাদা আলাদা পেমেন্ট পদ্ধতি প্রয়োগ করি।এটি একটি সাধারণ Strategy Design Pattern এর উদাহরণ যা বিভিন্ন এলগরিদমকে encapsulate (অন্তর্ভুক্ত) করে এবং তাদের একসাথে ব্যবহার করার সুযোগ দেয়।
Read more