观察者模式

  1. /**
  2. * The Subject interface declares a set of methods for managing subscribers.
  3. */
  4. interface Subject {
  5. // Attach an observer to the subject.
  6. attach(observer: Observer): void;
  7. // Detach an observer from the subject.
  8. detach(observer: Observer): void;
  9. // Notify all observers about an event.
  10. notify(): void;
  11. }
  12. /**
  13. * The Subject owns some important state and notifies observers when the state
  14. * changes.
  15. */
  16. class ConcreteSubject implements Subject {
  17. /**
  18. * @type {number} For the sake of simplicity, the Subject's state, essential
  19. * to all subscribers, is stored in this variable.
  20. */
  21. public state: number;
  22. /**
  23. * @type {Observer[]} List of subscribers. In real life, the list of
  24. * subscribers can be stored more comprehensively (categorized by event
  25. * type, etc.).
  26. */
  27. private observers: Observer[] = [];
  28. /**
  29. * The subscription management methods.
  30. */
  31. public attach(observer: Observer): void {
  32. console.log('Subject: Attached an observer.');
  33. this.observers.push(observer);
  34. }
  35. public detach(observer: Observer): void {
  36. const observerIndex = this.observers.indexOf(observer);
  37. this.observers.splice(observerIndex, 1);
  38. console.log('Subject: Detached an observer.');
  39. }
  40. /**
  41. * Trigger an update in each subscriber.
  42. */
  43. public notify(): void {
  44. console.log('Subject: Notifying observers...');
  45. for (const observer of this.observers) {
  46. observer.update(this);
  47. }
  48. }
  49. /**
  50. * Usually, the subscription logic is only a fraction of what a Subject can
  51. * really do. Subjects commonly hold some important business logic, that
  52. * triggers a notification method whenever something important is about to
  53. * happen (or after it).
  54. */
  55. public someBusinessLogic(): void {
  56. console.log('\nSubject: I\'m doing something important.');
  57. this.state = Math.floor(Math.random() * (10 + 1));
  58. console.log(`Subject: My state has just changed to: ${this.state}`);
  59. this.notify();
  60. }
  61. }
  62. /**
  63. * The Observer interface declares the update method, used by subjects.
  64. */
  65. interface Observer {
  66. // Receive update from subject.
  67. update(subject: Subject): void;
  68. }
  69. /**
  70. * Concrete Observers react to the updates issued by the Subject they had been
  71. * attached to.
  72. */
  73. class ConcreteObserverA implements Observer {
  74. public update(subject: Subject): void {
  75. if (subject.state < 3) {
  76. console.log('ConcreteObserverA: Reacted to the event.');
  77. }
  78. }
  79. }
  80. class ConcreteObserverB implements Observer {
  81. public update(subject: Subject): void {
  82. if (subject.state === 0 || subject.state >= 2) {
  83. console.log('ConcreteObserverB: Reacted to the event.');
  84. }
  85. }
  86. }
  87. /**
  88. * The client code.
  89. */
  90. const subject = new ConcreteSubject();
  91. const observer1 = new ConcreteObserverA();
  92. subject.attach(observer1);
  93. const observer2 = new ConcreteObserverB();
  94. subject.attach(observer2);
  95. subject.someBusinessLogic();
  96. subject.someBusinessLogic();
  97. subject.detach(observer2);
  98. subject.someBusinessLogic();

单例模式

  1. /**
  2. * The Singleton class defines the `getInstance` method that lets clients access
  3. * the unique singleton instance.
  4. */
  5. class Singleton {
  6. private static instance: Singleton;
  7. /**
  8. * The Singleton's constructor should always be private to prevent direct
  9. * construction calls with the `new` operator.
  10. */
  11. private constructor() { }
  12. /**
  13. * The static method that controls the access to the singleton instance.
  14. *
  15. * This implementation let you subclass the Singleton class while keeping
  16. * just one instance of each subclass around.
  17. */
  18. public static getInstance(): Singleton {
  19. if (!Singleton.instance) {
  20. Singleton.instance = new Singleton();
  21. }
  22. return Singleton.instance;
  23. }
  24. /**
  25. * Finally, any singleton should define some business logic, which can be
  26. * executed on its instance.
  27. */
  28. public someBusinessLogic() {
  29. // ...
  30. }
  31. }
  32. /**
  33. * The client code.
  34. */
  35. function clientCode() {
  36. const s1 = Singleton.getInstance();
  37. const s2 = Singleton.getInstance();
  38. if (s1 === s2) {
  39. console.log('Singleton works, both variables contain the same instance.');
  40. } else {
  41. console.log('Singleton failed, variables contain different instances.');
  42. }
  43. }
  44. clientCode();

享元模式

  1. /**
  2. * The Flyweight stores a common portion of the state (also called intrinsic
  3. * state) that belongs to multiple real business entities. The Flyweight accepts
  4. * the rest of the state (extrinsic state, unique for each entity) via its
  5. * method parameters.
  6. */
  7. class Flyweight {
  8. private sharedState: any;
  9. constructor(sharedState: any) {
  10. this.sharedState = sharedState;
  11. }
  12. public operation(uniqueState): void {
  13. const s = JSON.stringify(this.sharedState);
  14. const u = JSON.stringify(uniqueState);
  15. console.log(`Flyweight: Displaying shared (${s}) and unique (${u}) state.`);
  16. }
  17. }
  18. /**
  19. * The Flyweight Factory creates and manages the Flyweight objects. It ensures
  20. * that flyweights are shared correctly. When the client requests a flyweight,
  21. * the factory either returns an existing instance or creates a new one, if it
  22. * doesn't exist yet.
  23. */
  24. class FlyweightFactory {
  25. private flyweights: {[key: string]: Flyweight} = <any>{};
  26. constructor(initialFlyweights: string[][]) {
  27. for (const state of initialFlyweights) {
  28. this.flyweights[this.getKey(state)] = new Flyweight(state);
  29. }
  30. }
  31. /**
  32. * Returns a Flyweight's string hash for a given state.
  33. */
  34. private getKey(state: string[]): string {
  35. return state.join('_');
  36. }
  37. /**
  38. * Returns an existing Flyweight with a given state or creates a new one.
  39. */
  40. public getFlyweight(sharedState: string[]): Flyweight {
  41. const key = this.getKey(sharedState);
  42. if (!(key in this.flyweights)) {
  43. console.log('FlyweightFactory: Can\'t find a flyweight, creating new one.');
  44. this.flyweights[key] = new Flyweight(sharedState);
  45. } else {
  46. console.log('FlyweightFactory: Reusing existing flyweight.');
  47. }
  48. return this.flyweights[key];
  49. }
  50. public listFlyweights(): void {
  51. const count = Object.keys(this.flyweights).length;
  52. console.log(`\nFlyweightFactory: I have ${count} flyweights:`);
  53. for (const key in this.flyweights) {
  54. console.log(key);
  55. }
  56. }
  57. }
  58. /**
  59. * The client code usually creates a bunch of pre-populated flyweights in the
  60. * initialization stage of the application.
  61. */
  62. const factory = new FlyweightFactory([
  63. ['Chevrolet', 'Camaro2018', 'pink'],
  64. ['Mercedes Benz', 'C300', 'black'],
  65. ['Mercedes Benz', 'C500', 'red'],
  66. ['BMW', 'M5', 'red'],
  67. ['BMW', 'X6', 'white'],
  68. // ...
  69. ]);
  70. factory.listFlyweights();
  71. // ...
  72. function addCarToPoliceDatabase(
  73. ff: FlyweightFactory, plates: string, owner: string,
  74. brand: string, model: string, color: string,
  75. ) {
  76. console.log('\nClient: Adding a car to database.');
  77. const flyweight = ff.getFlyweight([brand, model, color]);
  78. // The client code either stores or calculates extrinsic state and passes it
  79. // to the flyweight's methods.
  80. flyweight.operation([plates, owner]);
  81. }
  82. addCarToPoliceDatabase(factory, 'CL234IR', 'James Doe', 'BMW', 'M5', 'red');
  83. addCarToPoliceDatabase(factory, 'CL234IR', 'James Doe', 'BMW', 'X1', 'red');
  84. factory.listFlyweights();