| Pattern | Category | Purpose |
|---|---|---|
| Singleton | Creational | Instance တစ်ခုပဲ ရှိစေ |
| Factory | Creational | Object ဆောက်နည်းကို encapsulate |
| Observer | Behavioral | Event/subscription system |
| Strategy | Behavioral | Algorithm ကို swap လုပ်နိုင် |
| Module | Structural | Private scope, public API |
// Singleton = class instance တစ်ခုပဲ ရှိနိုင် (e.g., Config, Logger, DB connection)
class Config {
static #instance = null;
#settings = {};
constructor() {
if (Config.#instance) {
return Config.#instance; // existing instance ပြန်ပေး
}
this.#settings = { theme: "dark", lang: "en", version: "1.0" };
Config.#instance = this;
}
get(key) { return this.#settings[key]; }
set(key, value) { this.#settings[key] = value; }
getAll() { return { ...this.#settings }; }
}
const c1 = new Config();
const c2 = new Config();
c1 === c2; // true — same instance!
c1.set("theme", "light");
c2.get("theme"); // "light" — same object!
// Modern Singleton with module (cleaner)
// config.js module exports a single instance
// ES modules are singletons by default (cached after first import)
// Factory = object creation ကို central function/class ထဲ ထားခြင်း
class Button {
constructor(text, color) {
this.text = text;
this.color = color;
this.type = "generic";
}
render() { return `[${this.type.toUpperCase()} Button: ${this.text}]`; }
}
class PrimaryButton extends Button {
constructor(text) { super(text, "blue"); this.type = "primary"; }
}
class DangerButton extends Button {
constructor(text) { super(text, "red"); this.type = "danger"; }
}
class SuccessButton extends Button {
constructor(text) { super(text, "green"); this.type = "success"; }
}
// Factory — caller doesn't need to know which class
class ButtonFactory {
static create(type, text) {
switch (type) {
case "primary": return new PrimaryButton(text);
case "danger": return new DangerButton(text);
case "success": return new SuccessButton(text);
default: throw new Error(`Unknown button type: ${type}`);
}
}
}
const btn1 = ButtonFactory.create("primary", "Submit");
const btn2 = ButtonFactory.create("danger", "Delete");
const btn3 = ButtonFactory.create("success", "Save");
btn1.render(); // "[PRIMARY Button: Submit]"
btn2.render(); // "[DANGER Button: Delete]"
// Add new type → only need to add case in factory, not change callers
// Observer = "publish/subscribe" — event ပေးပို့ → subscribers ခံယူ
// Real use: DOM events, Vue reactivity, Node.js EventEmitter
class EventEmitter {
#events = {};
on(event, listener) {
if (!this.#events[event]) this.#events[event] = [];
this.#events[event].push(listener);
return this; // chaining support
}
off(event, listener) {
if (!this.#events[event]) return;
this.#events[event] = this.#events[event].filter(l => l !== listener);
}
emit(event, ...args) {
(this.#events[event] || []).forEach(listener => listener(...args));
}
once(event, listener) {
const wrapper = (...args) => {
listener(...args);
this.off(event, wrapper);
};
this.on(event, wrapper);
}
}
// Usage
const shop = new EventEmitter();
// Subscribe
shop.on("order", (item, qty) => console.log(`Order: ${qty}x ${item}`));
shop.on("order", (item) => console.log(`Stock check for ${item}`));
shop.once("open", () => console.log("Shop opened! (once only)"));
// Emit events
shop.emit("order", "Book", 3);
// "Order: 3x Book"
// "Stock check for Book"
shop.emit("open"); // "Shop opened! (once only)"
shop.emit("open"); // nothing — once already fired
// Strategy = algorithm ကို runtime မှာ swap လုပ်နိုင်
// e.g., payment methods, sorting algorithms, validation rules
class PaymentProcessor {
#strategy;
constructor(strategy) {
this.#strategy = strategy;
}
setStrategy(strategy) {
this.#strategy = strategy;
}
pay(amount) {
return this.#strategy.process(amount);
}
}
// Strategies
const CreditCard = {
process(amount) {
return `💳 Charged $${amount} via Credit Card (2% fee: $${(amount*0.02).toFixed(2)})`;
}
};
const PayPal = {
process(amount) {
return `🔵 Sent $${amount} via PayPal (1.5% fee: $${(amount*0.015).toFixed(2)})`;
}
};
const Crypto = {
process(amount) {
return `₿ Transferred $${amount} via Bitcoin (network fee: $2.00)`;
}
};
const KPay = {
process(amount) {
return `📱 Paid $${amount} via KPay (0% fee!)`;
}
};
const processor = new PaymentProcessor(CreditCard);
processor.pay(100); // "💳 Charged $100 via Credit Card..."
processor.setStrategy(PayPal);
processor.pay(100); // "🔵 Sent $100 via PayPal..."
processor.setStrategy(KPay);
processor.pay(100); // "📱 Paid $100 via KPay..."
// New payment method → add new strategy, don't change PaymentProcessor
// Module = encapsulate private state, expose public API
// Modern: use ES modules (import/export)
// IIFE Module (pre-modules)
const UserStore = (function() {
let users = []; // private
let nextId = 1; // private
function findById(id) { // private helper
return users.find(u => u.id === id);
}
return {
// Public API
addUser(name, email) {
const user = { id: nextId++, name, email };
users.push(user);
return user;
},
getUser(id) { return findById(id) || null; },
getAllUsers() { return [...users]; }, // copy, not ref
deleteUser(id) {
const idx = users.findIndex(u => u.id === id);
if (idx === -1) return false;
users.splice(idx, 1);
return true;
},
get count() { return users.length; }
};
})();
UserStore.addUser("Ko Ko", "ko@example.com");
UserStore.addUser("Ma Ma", "ma@example.com");
UserStore.getUser(1); // { id: 1, name: "Ko Ko", ... }
UserStore.count; // 2
// UserStore.users → undefined (private)
← JS 12 | Next: JS 14 → Error Handling →