Applying Observer and Strategy Patterns for Smart Home Security System and Climate Control

This unit focuses on two design patterns: Observer and Strategy. We'll use these patterns to enable responsive security and flexible climate control in our smart home system.

Quick Summary
  1. Observer Pattern:

    • Purpose: Allows an object (observer) to watch another (subject) and be notified of changes.
    • Steps:
      • Define a Subject class with registration, unregistration, and notification methods (e.g., for a SecuritySystem).
      • Implement observer interfaces or abstract classes that react to changes (e.g., SecurityApp, SecurityLight).
  2. Strategy Pattern:

    • Purpose: Defines a family of algorithms and makes them interchangeable.
    • Steps:
      • Define a strategy interface or abstract class with a method for the desired behavior (e.g., TemperatureControlStrategy for controlling temperature).
      • Implement specific strategies with concrete behaviors (e.g., HeatingStrategy, CoolingStrategy).
      • Create a context to use and switch strategies (e.g., a ClimateControl system).
Implementing the Observer Pattern for the Security System

Here is the complete code to implement the Observer pattern using TypeScript:

// Define the Observer interface
interface Observer {
    update(subject: Subject): void;
}

// Define the Subject class
class Subject {
    private observers: Observer[] = [];

    public registerObserver(observer: Observer): void {
        this.observers.push(observer);
    }

    public unregisterObserver(observer: Observer): void {
        this.observers = this.observers.filter(obs => obs !== observer);
    }

    protected notifyObservers(): void {
        for (const observer of this.observers) {
            observer.update(this);
        }
    }
}

// Define the SecuritySystem class
class SecuritySystem extends Subject {
    private state: string | null = null;

    public setState(state: string): void {
        this.state = state;
        this.notifyObservers();
    }
    
    public getState(): string | null {
        return this.state;
    }
}

// Implement the SecurityApp observer
class SecurityApp implements Observer {
    public update(subject: Subject): void {
        if (subject instanceof SecuritySystem) {
            console.log(`SecurityApp notified. New state: ${subject.getState()}`);
        }
    }
}

// Implement the SecurityLight observer
class SecurityLight implements Observer {
    public update(subject: Subject): void {
        if (subject instanceof SecuritySystem) {
            console.log(`SecurityLight activated! State: ${subject.getState()}`);
        }
    }
}

// Example usage
const securitySystem = new SecuritySystem();
const app = new SecurityApp();
const light = new SecurityLight();

securitySystem.registerObserver(app);
securitySystem.registerObserver(light);
securitySystem.setState("Intrusion Detected");

// Expected Output:
// SecurityApp notified. New state: Intrusion Detected
// SecurityLight activated! State: Intrusion Detected

The securitySystem instance notifies both SecurityApp and SecurityLight when the state changes to "Intrusion Detected."

Implementing the Strategy Pattern for Climate Control

Here is the complete code to implement the Strategy pattern using TypeScript:

// Define the TemperatureControlStrategy interface
interface TemperatureControlStrategy {
    controlTemperature(temperature: number): void;
}

// Implement the HeatingStrategy
class HeatingStrategy implements TemperatureControlStrategy {
    public controlTemperature(temperature: number): void {
        console.log(`Heating to ${temperature} degrees.`);
    }
}

// Implement the CoolingStrategy
class CoolingStrategy implements TemperatureControlStrategy {
    public controlTemperature(temperature: number): void {
        console.log(`Cooling to ${temperature} degrees.`);
    }
}

// Define the ClimateControl context
class ClimateControl {
    private strategy: TemperatureControlStrategy;

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

    public setStrategy(strategy: TemperatureControlStrategy): void {
        this.strategy = strategy;
    }
    
    public controlTemperature(temperature: number): void {
        this.strategy.controlTemperature(temperature);
    }
}

// Example usage
const climateControl = new ClimateControl(new HeatingStrategy());
climateControl.controlTemperature(22); // Expected Output: Heating to 22 degrees.

climateControl.setStrategy(new CoolingStrategy());
climateControl.controlTemperature(18); // Expected Output: Cooling to 18 degrees.

The ClimateControl instance can switch between HeatingStrategy and CoolingStrategy to control the temperature accordingly.

Conclusion

By implementing the Observer and Strategy patterns, our smart home system becomes more robust and versatile. The Observer pattern ensures that our security system is responsive by notifying observers of changes, while the Strategy pattern provides flexibility to our climate control system by allowing different temperature control strategies to be used interchangeably. This combination leads to a more adaptable and efficient smart home environment.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal