Programming Languages

Design Patterns in Modern Languages: Singleton, Factory, Observer, Strategy

private logs: string[] = [];

private constructor() {
// Private constructor
}

static getInstance(): Logger {
if (!Logger.instance) {
Logger.instance = new Logger();
}
return Logger.instance;
}

log(message: string): void {
const timestamp = new Date().toISOString();
this.logs.push([${timestamp}] ${message});
console.log([${timestamp}] ${message});
}

getLogs(): string[] {
return [...this.logs];
}```
}

// Usage
const logger1 = Logger.getInstance();
const logger2 = Logger.getInstance();

logger1.log("Application started");
console.log(logger1 === logger2); // true - same instance


### Python Implementation

```python
class ConfigManager:
```python
"""Thread-safe singleton with __new__."""
_instance = None
_lock = threading.Lock()

def __new__(cls):
    if cls._instance is None:
        with cls._lock:
            if cls._instance is None:
                cls._instance = super().__new__(cls)
                cls._instance._initialized = False
    return cls._instance

def __init__(self):
    if self._initialized:
        return
    self.config = self._load_config()
    self._initialized = True

def _load_config(self):
    return {"api_url": "https://api.contoso.com", "timeout": 30}

def get(self, key):
    return self.config.get(key)

Usage

config1 = ConfigManager()
config2 = ConfigManager()
print(config1 is config2) # True


**Modern alternative - Dependency Injection:**

```typescript
// Instead of Singleton, use DI container
interface ILogger {
```text
log(message: string): void;```
}

class ConsoleLogger implements ILogger {
```javascript
log(message: string): void {
    console.log(message);
}```
}

// Register in DI container
container.register<ILogger>("ILogger", ConsoleLogger, { lifecycle: "singleton" });

// Inject dependency
class UserService {
```text
constructor(private logger: ILogger) {}

createUser(name: string): void {
    this.logger.log(`Creating user: ${name}`);
}```
}

Factory Pattern

Purpose

Factory Pattern

Create objects without specifying exact class, delegating instantiation to subclasses.

Simple Factory (C#)

// Product interface
public interface INotification
{
```text
void Send(string message);```
}

// Concrete products
public class EmailNotification : INotification
{
```text
public void Send(string message)
{
    Console.WriteLine($"Email: {message}");
}```
}

public class SMSNotification : INotification
{
```text
public void Send(string message)
{
    Console.WriteLine($"SMS: {message}");
}```
}

public class PushNotification : INotification
{
```text
public void Send(string message)
{
    Console.WriteLine($"Push: {message}");
}```
}

// Factory
public class NotificationFactory
{
```javascript
public static INotification Create(string type)
{
    return type.ToLower() switch
    {
        "email" => new EmailNotification(),
        "sms" => new SMSNotification(),
        "push" => new PushNotification(),
        _ => throw new ArgumentException($"Unknown type: {type}")
    };
}```
}

// Usage
var notification = NotificationFactory.Create("email");
notification.Send("Hello, World!");

Factory Method (TypeScript)

// Product interface
interface IDocument {
```text
open(): void;
save(): void;```
}

// Concrete products
class PDFDocument implements IDocument {
```javascript
open(): void {
    console.log("Opening PDF document");
}

save(): void {
    console.log("Saving PDF document");
}```
}

class WordDocument implements IDocument {
```javascript
open(): void {
    console.log("Opening Word document");
}

save(): void {
    console.log("Saving Word document");
}```
}

// Creator abstract class
abstract class DocumentCreator {
```javascript
abstract createDocument(): IDocument;

openDocument(): void {
    const doc = this.createDocument();
    doc.open();
}```
}

// Concrete creators
class PDFCreator extends DocumentCreator {
```text
createDocument(): IDocument {
    return new PDFDocument();
}```
}

class WordCreator extends DocumentCreator {
```text
createDocument(): IDocument {
    return new WordDocument();
}```
}

// Usage
const pdfCreator = new PDFCreator();
pdfCreator.openDocument();  // Opens PDF

const wordCreator = new WordCreator();
wordCreator.openDocument();  // Opens Word

Abstract Factory (Python)

from abc import ABC, abstractmethod

## Abstract products
class Button(ABC):
```python
@abstractmethod
def render(self): pass

class Checkbox(ABC):

@abstractmethod
def render(self): pass

Abstract products

Concrete products - Windows

class WindowsButton(Button):

def render(self):
    return "Rendering Windows button"

class WindowsCheckbox(Checkbox):

def render(self):
    return "Rendering Windows checkbox"

Concrete products - Windows

Concrete products - macOS

class MacButton(Button):

def render(self):
    return "Rendering Mac button"

class MacCheckbox(Checkbox):

def render(self):
    return "Rendering Mac checkbox"

Concrete products - macOS

Abstract factory

Abstract factory

Figure: Configuration and management dashboard with status overview.

class GUIFactory(ABC):

@abstractmethod
def create_button(self) -> Button: pass

![Abstract factory](/images/articles/programming-languages/2025-08-04-design-patterns-modern-languages-singleton-factory-observer-sec5-implementation.jpg)


@abstractmethod
def create_checkbox(self) -> Checkbox: pass

Concrete factories

Concrete factories

Figure: Configuration and management dashboard with status overview.

class WindowsFactory(GUIFactory):

def create_button(self) -> Button:
    return WindowsButton()

![Concrete factories](/images/articles/programming-languages/2025-08-04-design-patterns-modern-languages-singleton-factory-observer-sec6-implementation.jpg)


def create_checkbox(self) -> Checkbox:
    return WindowsCheckbox()

class MacFactory(GUIFactory):

def create_button(self) -> Button:
    return MacButton()

def create_checkbox(self) -> Checkbox:
    return MacCheckbox()

Usage

def create_ui(factory: GUIFactory):

button = factory.create_button()
checkbox = factory.create_checkbox()
print(button.render())
print(checkbox.render())

import platform
factory = WindowsFactory() if platform.system() == "Windows" else MacFactory()
create_ui(factory)

Usage

Usage

Usage


## Observer Pattern


### Purpose

![Observer Pattern](/images/articles/programming-languages/2025-08-04-design-patterns-modern-languages-singleton-factory-observer-sec8-architecture.jpg)


Define one-to-many dependency where state changes notify all dependents automatically.

### C# with Events

```csharp
// Subject
public class StockMarket
{
```javascript
public event EventHandler<StockPriceChangedEventArgs> PriceChanged;

private decimal _price;

public decimal Price
{
    get => _price;
    set
    {
        if (_price != value)
        {
            var oldPrice = _price;
            _price = value;
            OnPriceChanged(new StockPriceChangedEventArgs(oldPrice, value));
        }
    }
}

protected virtual void OnPriceChanged(StockPriceChangedEventArgs e)
{
    PriceChanged?.Invoke(this, e);
}```
}

public class StockPriceChangedEventArgs : EventArgs
{
```text
public decimal OldPrice { get; }
public decimal NewPrice { get; }

public StockPriceChangedEventArgs(decimal oldPrice, decimal newPrice)
{
    OldPrice = oldPrice;
    NewPrice = newPrice;
}```
}

// Observers
public class StockDisplay
{
```python
public void Subscribe(StockMarket market)
{
    market.PriceChanged += OnPriceChanged;
}

private void OnPriceChanged(object sender, StockPriceChangedEventArgs e)
{
    Console.WriteLine($"Display: Price changed from {e.OldPrice} to {e.NewPrice}");
}```
}

public class StockAlert
{
```text
private decimal _threshold;

public StockAlert(decimal threshold)
{
    _threshold = threshold;
}

public void Subscribe(StockMarket market)
{
    market.PriceChanged += OnPriceChanged;
}

private void OnPriceChanged(object sender, StockPriceChangedEventArgs e)
{
    if (e.NewPrice > _threshold)
    {
        Console.WriteLine($"ALERT: Price exceeded {_threshold}!");
    }
}```
}

// Usage
var market = new StockMarket { Price = 100 };
var display = new StockDisplay();
var alert = new StockAlert(150);

display.Subscribe(market);
alert.Subscribe(market);

market.Price = 120;  // Triggers display
market.Price = 160;  // Triggers both display and alert

TypeScript with RxJS

import { Subject } from 'rxjs';
import { filter, map } from 'rxjs/operators';

interface User {
```yaml
id: number;
name: string;
status: 'online' | 'offline';```
}

class UserService {
```text
private userStatusSubject = new Subject<User>();

userStatus$ = this.userStatusSubject.asObservable();

updateUserStatus(user: User): void {
    this.userStatusSubject.next(user);
}```
}

// Observers
class NotificationService {
```javascript
constructor(private userService: UserService) {
    this.userService.userStatus$
        .pipe(filter(user => user.status === 'online'))
        .subscribe(user => {
            console.log(`Notification: ${user.name} is now online`);
        });
}```
}

class ActivityLogger {
```javascript
constructor(private userService: UserService) {
    this.userService.userStatus$.subscribe(user => {
        console.log(`Log: User ${user.id} status: ${user.status}`);
    });
}```
}

// Usage
const userService = new UserService();
const notifications = new NotificationService(userService);
const logger = new ActivityLogger(userService);

userService.updateUserStatus({ id: 1, name: 'Alice', status: 'online' });
// Output:
// Log: User 1 status: online
// Notification: Alice is now online

Python with Custom Observer

from abc import ABC, abstractmethod
from typing import List

## Observer interface
class Observer(ABC):
```python
@abstractmethod
def update(self, subject: 'Subject') -> None:
    pass

Observer interface

Subject

Subject

Figure: Configuration and management dashboard with status overview.

class Subject:

def __init__(self):
    self._observers: List[Observer] = []
    self._state = None

![Subject](/images/articles/programming-languages/2025-08-04-design-patterns-modern-languages-singleton-factory-observer-sec10-implementation.jpg)


def attach(self, observer: Observer) -> None:
    self._observers.append(observer)

def detach(self, observer: Observer) -> None:
    self._observers.remove(observer)

def notify(self) -> None:
    for observer in self._observers:
        observer.update(self)

@property
def state(self):
    return self._state

@state.setter
def state(self, value):
    self._state = value
    self.notify()

Concrete observers

Concrete observers

Figure: Configuration and management dashboard with status overview.

class EmailNotifier(Observer):

def update(self, subject: Subject) -> None:
    print(f"Email: State changed to {subject.state}")

class SMSNotifier(Observer):

def update(self, subject: Subject) -> None:
    if subject.state == "critical":
        print(f"SMS Alert: Critical state!")

class Logger(Observer):

def update(self, subject: Subject) -> None:

![Concrete observers](/images/articles/programming-languages/2025-08-04-design-patterns-modern-languages-singleton-factory-observer-sec11-monitoring.jpg)

    print(f"Log: State = {subject.state}")

Usage

Usage

Figure: Configuration and management dashboard with status overview.

subject = Subject()
email = EmailNotifier()
sms = SMSNotifier()
logger = Logger()

subject.attach(email)
subject.attach(sms)
subject.attach(logger)

subject.state = "normal" # All observers notified
subject.state = "critical" # SMS sends alert


## Strategy Pattern

### Purpose

![Strategy Pattern](/images/articles/programming-languages/2025-08-04-design-patterns-modern-languages-singleton-factory-observer-sec13-architecture.jpg)


Define family of algorithms, encapsulate each, make them interchangeable.

### C# Implementation

```csharp
// Strategy interface
public interface IPaymentStrategy
{
```text
void Pay(decimal amount);```
}

// Concrete strategies
public class CreditCardPayment : IPaymentStrategy
{
```sql
private string _cardNumber;

public CreditCardPayment(string cardNumber)
{
    _cardNumber = cardNumber;
}

public void Pay(decimal amount)
{
    Console.WriteLine($"Paid ${amount} with credit card {_cardNumber}");
}```
}

public class PayPalPayment : IPaymentStrategy
{
```text
private string _email;

public PayPalPayment(string email)
{
    _email = email;
}

public void Pay(decimal amount)
{
    Console.WriteLine($"Paid ${amount} via PayPal to {_email}");
}```
}

public class BitcoinPayment : IPaymentStrategy
{
```text
private string _walletAddress;

public BitcoinPayment(string walletAddress)
{
    _walletAddress = walletAddress;
}

public void Pay(decimal amount)
{
    Console.WriteLine($"Paid ${amount} in Bitcoin to {_walletAddress}");
}```
}

// Context
public class ShoppingCart
{
```text
private IPaymentStrategy _paymentStrategy;

public void SetPaymentStrategy(IPaymentStrategy strategy)
{
    _paymentStrategy = strategy;
}

public void Checkout(decimal amount)
{
    _paymentStrategy.Pay(amount);
}```
}

// Usage
var cart = new ShoppingCart();

cart.SetPaymentStrategy(new CreditCardPayment("1234-5678-9012-3456"));
cart.Checkout(99.99m);

cart.SetPaymentStrategy(new PayPalPayment("user@contoso.com"));
cart.Checkout(49.99m);

TypeScript with Functional Approach

// Strategy as function type
type CompressionStrategy = (data: string) => string;

// Concrete strategies as functions
const zipCompression: CompressionStrategy = (data) => {
```text
return `ZIP compressed: ${data}`;```
};

const gzipCompression: CompressionStrategy = (data) => {
```text
return `GZIP compressed: ${data}`;```
};

const lzmaCompression: CompressionStrategy = (data) => {
```text
return `LZMA compressed: ${data}`;```
};

// Context
class FileCompressor {
```text
private strategy: CompressionStrategy;

constructor(strategy: CompressionStrategy) {
    this.strategy = strategy;
}

setStrategy(strategy: CompressionStrategy): void {
    this.strategy = strategy;
}

compress(data: string): string {
    return this.strategy(data);
}```
}

// Usage
const compressor = new FileCompressor(zipCompression);
console.log(compressor.compress("data"));  // ZIP compressed: data

compressor.setStrategy(gzipCompression);
console.log(compressor.compress("data"));  // GZIP compressed: data

Python with Duck Typing

## Strategy classes (no interface needed in Python)
class QuickSort:
```python
def sort(self, data: list) -> list:
    if len(data) <= 1:
        return data
    pivot = data[len(data) // 2]
    left = [x for x in data if x < pivot]
    middle = [x for x in data if x == pivot]
    right = [x for x in data if x > pivot]
    return self.sort(left) + middle + self.sort(right)

class BubbleSort:

def sort(self, data: list) -> list:

![Strategy classes (no interface needed in Python)](/images/articles/programming-languages/2025-08-04-design-patterns-modern-languages-singleton-factory-observer-sec14-implementation.jpg)

    arr = data.copy()
    n = len(arr)
    for i in range(n):
        for j in range(0, n - i - 1):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
    return arr

class MergeSort:

def sort(self, data: list) -> list:
    if len(data) <= 1:
        return data
    mid = len(data) // 2
    left = self.sort(data[:mid])
    right = self.sort(data[mid:])
    return self._merge(left, right)

def _merge(self, left: list, right: list) -> list:
    result = []
    i = j = 0
    while i < len(left) and j < len(right):
        if left[i] < right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result.extend(left[i:])
    result.extend(right[j:])
    return result

Context

Context

Figure: Configuration and management dashboard with status overview.

class Sorter:

def __init__(self, strategy):
    self._strategy = strategy

![Context](/images/articles/programming-languages/2025-08-04-design-patterns-modern-languages-singleton-factory-observer-sec15-implementation.jpg)


def set_strategy(self, strategy):
    self._strategy = strategy

def sort(self, data: list) -> list:
    return self._strategy.sort(data)

Usage

Usage

Figure: Configuration and management dashboard with status overview.

data = [64, 34, 25, 12, 22, 11, 90]

sorter = Sorter(QuickSort())
print(sorter.sort(data)) # Quick sorted

sorter.set_strategy(BubbleSort())
print(sorter.sort(data)) # Bubble sorted


## Best Practices

1. **Singleton**: Use dependency injection instead when possible
2. **Factory**: Prefer factory methods for simple cases, abstract factory for families
3. **Observer**: Clean up subscriptions to prevent memory leaks
4. **Strategy**: Use functional approach in languages supporting first-class functions

![Best Practices](/images/articles/programming-languages/2025-08-04-design-patterns-modern-languages-singleton-factory-observer-sec17-bestpractice.jpg)

## Architecture Decision and Tradeoffs

When designing software development solutions with Programming Languages, consider these key architectural trade-offs:

| Approach | Best For | Tradeoff |
|----------|----------|----------|
| Managed / platform service | Rapid delivery, reduced ops burden | Less customisation, potential vendor lock-in |
| Custom / self-hosted | Full control, advanced tuning | Higher operational overhead and cost |

> **Recommendation:** Start with the managed approach for most workloads and move to custom only when specific requirements demand it.

## Validation and Versioning

- Last validated: April 2026
- Validate examples against your tenant, region, and SKU constraints before production rollout.
- Keep module, CLI, and SDK versions pinned in automation pipelines and review quarterly.

## Security and Governance Considerations

- Apply least-privilege access using RBAC roles and just-in-time elevation for admin tasks.
- Store secrets in managed secret stores and avoid embedding credentials in scripts or source files.
- Enable audit logging, data protection policies, and periodic access reviews for regulated workloads.

## Cost and Performance Notes

- Define budgets and alerts, then monitor usage and cost trends continuously after go-live.
- Baseline performance with synthetic and real-user checks before and after major changes.
- Scale resources with measured thresholds and revisit sizing after usage pattern changes.

## Official Microsoft References

- https://learn.microsoft.com/
- https://learn.microsoft.com/azure/
- https://learn.microsoft.com/power-platform/
- https://learn.microsoft.com/microsoft-365/

## Public Examples from Official Sources

- These examples are sourced from official public Microsoft documentation and sample repositories.
- Documentation examples: https://learn.microsoft.com/training/
- Sample repositories: https://github.com/microsoft
- Prefer adapting these examples to your tenant, subscriptions, and governance requirements before production use.

## Key Takeaways

- Singleton ensures single instance but hinders testability (prefer DI)
- Factory pattern abstracts object creation, improving flexibility
- Observer enables loose coupling between subject and observers
- Strategy allows runtime algorithm selection without conditional logic
- Design patterns solve recurring problems but shouldn't be overused

![Key Takeaways](/images/articles/programming-languages/2025-08-04-design-patterns-modern-languages-singleton-factory-observer-sec18-takeaway.jpg)


## Next Steps

- Learn **Decorator pattern** for adding behavior dynamically
- Explore **Command pattern** for undo/redo functionality
- Study **Repository pattern** for data access abstraction
- Master **CQRS pattern** for separating read/write operations


## Additional Resources

- [Design Patterns: Elements of Reusable Object-Oriented Software](https://en.wikipedia.org/wiki/Design_Patterns)
- [Refactoring Guru](https://refactoring.guru/design-patterns)
- [Source Making](https://sourcemaking.com/design_patterns)


---

*Patterns are solutions, not rules.*
AI Assistant
AI Assistant

Article Assistant

Ask me about this article

AI
Hi! I'm here to help you understand this article. Ask me anything about the content, concepts, or implementation details.