观察者模式
/** * The Subject interface declares a set of methods for managing subscribers. */interface Subject { // Attach an observer to the subject. attach(observer: Observer): void; // Detach an observer from the subject. detach(observer: Observer): void; // Notify all observers about an event. notify(): void;}/** * The Subject owns some important state and notifies observers when the state * changes. */class ConcreteSubject implements Subject { /** * @type {number} For the sake of simplicity, the Subject's state, essential * to all subscribers, is stored in this variable. */ public state: number; /** * @type {Observer[]} List of subscribers. In real life, the list of * subscribers can be stored more comprehensively (categorized by event * type, etc.). */ private observers: Observer[] = []; /** * The subscription management methods. */ public attach(observer: Observer): void { console.log('Subject: Attached an observer.'); this.observers.push(observer); } public detach(observer: Observer): void { const observerIndex = this.observers.indexOf(observer); this.observers.splice(observerIndex, 1); console.log('Subject: Detached an observer.'); } /** * Trigger an update in each subscriber. */ public notify(): void { console.log('Subject: Notifying observers...'); for (const observer of this.observers) { observer.update(this); } } /** * Usually, the subscription logic is only a fraction of what a Subject can * really do. Subjects commonly hold some important business logic, that * triggers a notification method whenever something important is about to * happen (or after it). */ public someBusinessLogic(): void { console.log('\nSubject: I\'m doing something important.'); this.state = Math.floor(Math.random() * (10 + 1)); console.log(`Subject: My state has just changed to: ${this.state}`); this.notify(); }}/** * The Observer interface declares the update method, used by subjects. */interface Observer { // Receive update from subject. update(subject: Subject): void;}/** * Concrete Observers react to the updates issued by the Subject they had been * attached to. */class ConcreteObserverA implements Observer { public update(subject: Subject): void { if (subject.state < 3) { console.log('ConcreteObserverA: Reacted to the event.'); } }}class ConcreteObserverB implements Observer { public update(subject: Subject): void { if (subject.state === 0 || subject.state >= 2) { console.log('ConcreteObserverB: Reacted to the event.'); } }}/** * The client code. */const subject = new ConcreteSubject();const observer1 = new ConcreteObserverA();subject.attach(observer1);const observer2 = new ConcreteObserverB();subject.attach(observer2);subject.someBusinessLogic();subject.someBusinessLogic();subject.detach(observer2);subject.someBusinessLogic();
单例模式
/** * The Singleton class defines the `getInstance` method that lets clients access * the unique singleton instance. */class Singleton { private static instance: Singleton; /** * The Singleton's constructor should always be private to prevent direct * construction calls with the `new` operator. */ private constructor() { } /** * The static method that controls the access to the singleton instance. * * This implementation let you subclass the Singleton class while keeping * just one instance of each subclass around. */ public static getInstance(): Singleton { if (!Singleton.instance) { Singleton.instance = new Singleton(); } return Singleton.instance; } /** * Finally, any singleton should define some business logic, which can be * executed on its instance. */ public someBusinessLogic() { // ... }}/** * The client code. */function clientCode() { const s1 = Singleton.getInstance(); const s2 = Singleton.getInstance(); if (s1 === s2) { console.log('Singleton works, both variables contain the same instance.'); } else { console.log('Singleton failed, variables contain different instances.'); }}clientCode();
享元模式
/** * The Flyweight stores a common portion of the state (also called intrinsic * state) that belongs to multiple real business entities. The Flyweight accepts * the rest of the state (extrinsic state, unique for each entity) via its * method parameters. */class Flyweight { private sharedState: any; constructor(sharedState: any) { this.sharedState = sharedState; } public operation(uniqueState): void { const s = JSON.stringify(this.sharedState); const u = JSON.stringify(uniqueState); console.log(`Flyweight: Displaying shared (${s}) and unique (${u}) state.`); }}/** * The Flyweight Factory creates and manages the Flyweight objects. It ensures * that flyweights are shared correctly. When the client requests a flyweight, * the factory either returns an existing instance or creates a new one, if it * doesn't exist yet. */class FlyweightFactory { private flyweights: {[key: string]: Flyweight} = <any>{}; constructor(initialFlyweights: string[][]) { for (const state of initialFlyweights) { this.flyweights[this.getKey(state)] = new Flyweight(state); } } /** * Returns a Flyweight's string hash for a given state. */ private getKey(state: string[]): string { return state.join('_'); } /** * Returns an existing Flyweight with a given state or creates a new one. */ public getFlyweight(sharedState: string[]): Flyweight { const key = this.getKey(sharedState); if (!(key in this.flyweights)) { console.log('FlyweightFactory: Can\'t find a flyweight, creating new one.'); this.flyweights[key] = new Flyweight(sharedState); } else { console.log('FlyweightFactory: Reusing existing flyweight.'); } return this.flyweights[key]; } public listFlyweights(): void { const count = Object.keys(this.flyweights).length; console.log(`\nFlyweightFactory: I have ${count} flyweights:`); for (const key in this.flyweights) { console.log(key); } }}/** * The client code usually creates a bunch of pre-populated flyweights in the * initialization stage of the application. */const factory = new FlyweightFactory([ ['Chevrolet', 'Camaro2018', 'pink'], ['Mercedes Benz', 'C300', 'black'], ['Mercedes Benz', 'C500', 'red'], ['BMW', 'M5', 'red'], ['BMW', 'X6', 'white'], // ...]);factory.listFlyweights();// ...function addCarToPoliceDatabase( ff: FlyweightFactory, plates: string, owner: string, brand: string, model: string, color: string,) { console.log('\nClient: Adding a car to database.'); const flyweight = ff.getFlyweight([brand, model, color]); // The client code either stores or calculates extrinsic state and passes it // to the flyweight's methods. flyweight.operation([plates, owner]);}addCarToPoliceDatabase(factory, 'CL234IR', 'James Doe', 'BMW', 'M5', 'red');addCarToPoliceDatabase(factory, 'CL234IR', 'James Doe', 'BMW', 'X1', 'red');factory.listFlyweights();