Design Patterns & SOLID Principles

"Architecting Robust Applications"

Design Pattern কোনো কোড নয়, এটা হলো কোড লেখার ব্লু-প্রিন্ট বা সমাধান। সফটওয়্যার ইঞ্জিনিয়ারিংয়ে কিছু কমন সমস্যা বারবার ফিরে আসে। সেই সমস্যাগুলো স্মার্টলি সমাধান করার নামই ডিজাইন প্যাটার্ন।

আর SOLID প্রিন্সিপাল হলো ভালো কোড লেখার ৫টি সুবর্ণ নিয়ম।

⭐ ১. Singleton Pattern: "একটাই রাজা" 👑

সমস্যা: এমন কিছু অবজেক্ট আছে যা অ্যাপ্লিকেশনে মাত্র একবারই তৈরি হওয়া উচিত। যেমন: ডাটাবেস কানেকশন বা কনফিগারেশন ফাইল।

সমাধান: Singleton প্যাটার্ন নিশ্চিত করে যে, একটি ক্লাসের মাত্র একটিই ইনস্ট্যান্স থাকবে।

💻 Code Implementation

class Database {
    constructor() {
        if (Database.instance) {
            return Database.instance;
        }
        
        this.connection = "Connected to MongoDB";
        this.randomID = Math.random();
        
        Database.instance = this;
    }

    getConnection() {
        return this.connection;
    }
}

const db1 = new Database();
const db2 = new Database();

console.log(db1 === db2); // true
console.log(db1.randomID === db2.randomID); // true

⭐ ২. Factory Pattern: "অবজেক্ট তৈরির মেশিন" 🏭

সমস্যা: বিভিন্ন ধরণের ইউজার আছে। প্রতিবার ম্যানুয়ালি new লেখা নোংরা কোড তৈরি করে।

সমাধান: একটা ফ্যাক্টরি ফাংশন বানাও, যে কন্ডিশন চেক করে সঠিক অবজেক্ট বানিয়ে দেবে।

💻 Code Implementation

class Admin {
    constructor() { this.role = "Admin"; this.access = ["read", "write"]; }
}

class Customer {
    constructor() { this.role = "Customer"; this.access = ["read"]; }
}

class UserFactory {
    static createUser(type) {
        switch (type) {
            case 'admin': return new Admin();
            case 'customer': return new Customer();
            default: throw new Error("Unknown user type");
        }
    }
}

const user1 = UserFactory.createUser('admin');
console.log(user1.role); // "Admin"

⭐ ৩. Observer Pattern: "YouTube Subscribe" 🔔

সমস্যা: যখন একটা ডাটা চেঞ্জ হয়, তখন অনেকগুলো জায়গায় আপডেট দরকার হয়।

সমাধান: Observer প্যাটার্ন (Pub/Sub)। Subject ইভেন্ট ছড়ায়, Observer শুনে কাজ করে।

💻 Code Implementation

class YouTubeChannel {
    constructor() {
        this.subscribers = [];
    }

    subscribe(fn) {
        this.subscribers.push(fn);
    }

    notify(videoTitle) {
        this.subscribers.forEach(subscriber => subscriber(videoTitle));
    }
}

const jsChannel = new YouTubeChannel();

jsChannel.subscribe(title => console.log(`User 1: New Video - ${title}`));
jsChannel.subscribe(title => console.log(`User 2: Notification - ${title}`));

jsChannel.notify("Advanced JS Tutorial");

Redux, DOM Event Listener এবং Node.js EventEmitter এই প্যাটার্নে কাজ করে।

⭐ ৪. Strategy Pattern: "গুগল ম্যাপস" 🗺️

সমস্যা: একই কাজ করার অনেকগুলো উপায় থাকে (যেমন পেমেন্ট)। if-else দিয়ে সব লজিক এক ক্লাসে লেখা কঠিন।

সমাধান: প্রতিটি উপায়কে আলাদা Strategy ক্লাসে ভাগ করো এবং রানটাইমে সিলেক্ট করো।

💻 Code Implementation

class Bkash {
    pay(amount) { console.log(`Paid ${amount} via Bkash`); }
}

class Stripe {
    pay(amount) { console.log(`Paid ${amount} via Stripe USD`); }
}

class Checkout {
    constructor(paymentMethod) {
        this.paymentMethod = paymentMethod;
    }
    
    setMethod(method) {
        this.paymentMethod = method;
    }

    processOrder(amount) {
        this.paymentMethod.pay(amount);
    }
}

const payment = new Checkout(new Bkash());
payment.processOrder(500); // Bkash

payment.setMethod(new Stripe());
payment.processOrder(500); // Stripe

⭐ ৫. Module Pattern: "প্রাইভেসি রক্ষা" 🛡️

ES6 এর আগে জাভাস্ক্রিপ্টে private ভেরিয়েবল ছিল না। তখন Closure ব্যবহার করে ডেটা হাইড করা হতো।

💻 Code Implementation

const BankAccount = (function() {
    let balance = 0;

    return {
        deposit(amount) {
            balance += amount;
            console.log(`Deposited: ${amount}`);
        },
        getBalance() {
            return balance;
        }
    };
})();

BankAccount.deposit(100);
console.log(BankAccount.getBalance()); // 100
// console.log(BankAccount.balance); // undefined (Private!)

⭐ ৬. Dependency Injection (DI): "সরঞ্জাম ধার নেওয়া" 🧰

সমস্যা: ক্লাসের ভেতরেই new Service() কল করলে Tightly Coupled হয়। টেস্টিং কঠিন হয়।

সমাধান: বাইরে থেকে ডিপেন্ডেন্সি পাস করো।

❌ Without DI:

class App {
    constructor() {
        this.db = new MySQLDatabase(); // Fixed! Change করা যাবে না
    }
}

✅ With DI:

class App {
    constructor(database) {
        this.db = database; // বাইরে থেকে যা দেবে
    }
}
const myApp = new App(new MongoDatabase()); // Flexible

⭐ ৭. SOLID Principles (The Senior Constitution) 📜

S — Single Responsibility Principle (SRP)

একটি ক্লাসের বা ফাংশনের একটাই কাজ থাকা উচিত।

O — Open/Closed Principle

Extension এর জন্য ওপেন, Modification এর জন্য ক্লোজড।

L — Liskov Substitution Principle (LSP)

চাইল্ড ক্লাস অবশ্যই প্যারেন্ট ক্লাসের বিকল্প হতে হবে।

I — Interface Segregation Principle

ছোট ছোট স্পেসিফিক ইন্টারফেস ভালো।

D — Dependency Inversion Principle

High-level মডিউল Low-level মডিউলের ওপর সরাসরি নির্ভর করবে না।

⭐ ৮. Real-World Architecture: Notification System 🚀

// 1. Singleton (Config)
const AppConfig = {
    apiKey: "XYZ_SECRET",
    env: "production"
};

// 2. Strategy (Methods)
class EmailSender { send(msg) { console.log(`📧 Sending Email: ${msg}`); } }
class SMSSender { send(msg) { console.log(`📱 Sending SMS: ${msg}`); } }

// 3. Factory (Choice)
class NotifierFactory {
    static getNotifier(type) {
        return type === 'email' ? new EmailSender() : new SMSSender();
    }
}

// 4. Observer (System)
class System {
    constructor() { this.observers = []; }
    
    subscribe(fn) { this.observers.push(fn); }
    
    triggerEvent(msg) {
        this.observers.forEach(fn => fn(msg));
    }
}

// --- Usage ---
const mySystem = new System();

mySystem.subscribe((msg) => {
    const sender = NotifierFactory.getNotifier('email');
    sender.send(msg);
});

mySystem.triggerEvent("Welcome to Senior JS Course!");

🧠 ৯. Senior Interview Questions

Q1: Singleton Pattern এর সমস্যা কী?

উত্তর: এটি গ্লোবাল স্টেটের মতো আচরণ করে। টেস্টিংয়ের সময় একে মক (Mock) করা কঠিন হয়।

Q2: Redux কোন প্যাটার্ন ফলো করে?

উত্তর: Observer Pattern (State change হলে UI সাবস্ক্রাইব করে) এবং Singleton (পুরো অ্যাপে একটাই Store থাকে)।

Q3: Composition vs Inheritance - কোনটা প্রেফার করবে?

উত্তর: Composition। কারণ ইনহেরিটেন্স কোডকে Tightly Coupled করে।

🚀 অধ্যায় ২২ সারাংশ (Checklist)

  • Singleton: একটাই ইনস্ট্যান্স
  • Factory: অবজেক্ট বানানোর লজিক আলাদা করা
  • Observer: ইভেন্ট লিসেনিং সিস্টেম
  • Strategy: রানটাইমে অ্যালগরিদম বদলানো
  • SOLID: ক্লিন আর্কিটেকচারের ৫টি স্তম্ভ

Next Step: আমাদের আর্কিটেকচার শেখা শেষ। এখন কোড ক্লিন রাখার জন্য এবং ভুল এড়ানোর জন্য আমাদের কিছু নিয়ম মানতে হবে। পরের অধ্যায়: "Clean Code & Best Practices"।

🔒 কপিরাইট সুরক্ষিত কন্টেন্ট 🔒

কপি, স্ক্রিনশট, প্রিন্ট করা সম্পূর্ণ নিষিদ্ধ।