[Design Patterns in JavaScript: A Comprehensive Guide - DEV Community](https://dev.to/topefasasi/js-design-patterns-a-comprehensive-guide-h3m)
気になったパターンのみ。
## Singleton Pattern
クラスのインスタンスの数を制限し、アプリケーション全体で単一の共有インスタンスにアクセスできるようにする場合に便利。
```js
// Implementation example of the Singleton Pattern
class Singleton {
constructor() {
if (!Singleton.instance) {
// Initialize the instance
Singleton.instance = this;
}
return Singleton.instance;
}
}
const instance1 = new Singleton();
const instance2 = new Singleton();
console.log(instance1 === instance2); // Output: true
```
## Factory Pattern
初期化するクラスを振り分けたい場合。
クラスをFactoryする。
```js
// Implementation example of the Factory Pattern
class Car {
constructor(make, model) {
this.make = make;
this.model = model;
}
}
class CarFactory {
createCar(make, model) {
return new Car(make, model);
}
}
const factory = new CarFactory();
const myCar = factory.createCar("Tope", "Model 1");
```
## Decorator Pattern
インスタンスをデコレータークラスの引数に入れて初期化。
オブジェクトの機能を強化できる。
```js
// Implementation example of the Decorator Pattern
class Coffee {
getCost() {
return 1;
}
}
class CoffeeDecorator {
constructor(coffee) {
this.coffee = coffee;
}
getCost() {
return this.coffee.getCost() + 0.5;
}
}
const myCoffee = new Coffee();
const coffeeWithMilk = new CoffeeDecorator(myCoffee);
console.log(coffeeWithMilk.getCost()); // Output: 1.5
```
## Facade Pattern
簡素化されたインターフェースを準備して、基礎となる実装の詳細を隠す。
```js
// Implementation example of the Facade Pattern
class SubsystemA {
operationA() {
console.log("Subsystem A operation.");
}
}
class SubsystemB {
operationB() {
console.log("Subsystem B operation.");
}
}
class Facade {
constructor() {
this.subsystemA = new SubsystemA();
this.subsystemB = new SubsystemB();
}
operation() {
this.subsystemA.operationA();
this.subsystemB.operationB();
}
}
const facade = new Facade();
facade.operation(); // Output: "Subsystem A operation." "Subsystem B operation."
```
## Adapter Pattern
互換性のないインターフェイスを持つオブジェクト間のブリッジとして機能させる。
```js
// Implementation
class LegacyPrinter {
printLegacy(text) {
console.log(`Legacy Printing: ${text}`);
}
}
// Target interface
class Printer {
print(text) {}
}
// Adapter
class PrinterAdapter extends Printer {
constructor() {
super();
this.legacyPrinter = new LegacyPrinter();
}
print(text) {
this.legacyPrinter.printLegacy(text);
}
}
// Usage
const printer = new PrinterAdapter();
printer.print("Hello, World!"); // Output: "Legacy Printing: Hello, World!"
```
## Composite Pattern
管理者(マネージャー)を作れる。
```js
// Implementation
class Employee {
constructor(name) {
this.name = name;
}
print() {
console.log(`Employee: ${this.name}`);
}
}
// Composite
class Manager extends Employee {
constructor(name) {
super(name);
this.employees = [];
}
add(employee) {
this.employees.push(employee);
}
remove(employee) {
const index = this.employees.indexOf(employee);
if (index !== -1) {
this.employees.splice(index, 1);
}
}
print() {
console.log(`Manager: ${this.name}`);
for (const employee of this.employees) {
employee.print();
}
}
}
// Usage
const john = new Employee("John Doe");
const jane = new Employee("Jane Smith");
const mary = new Manager("Mary Johnson");
mary.add(john);
mary.add(jane);
const peter = new Employee("Peter Brown");
const bob = new Manager("Bob Williams");
bob.add(peter);
bob.add(mary);
bob.print();
```
## Observer Pattern
オブザーバーをサブジェクトに突っ込むことにより、イベント型の通信が促進される。
「こんな時に実行されたい」イベントを追加できる。`addEventListener` のイメージ。
```js
// Implementation example of the Observer Pattern
class Subject {
constructor() {
this.observers = [];
}
addObserver(observer) {
this.observers.push(observer);
}
removeObserver(observer) {
const index = this.observers.indexOf(observer);
if (index !== -1) {
this.observers.splice(index, 1);
}
}
notifyObservers() {
this.observers.forEach((observer) => observer.update());
}
}
class Observer {
update() {
console.log("Observer is notified of changes.");
}
}
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.addObserver(observer1);
subject.addObserver(observer2);
subject.notifyObservers(); // Output: "Observer is notified of changes." "Observer is notified of changes."
```
## Strategy Pattern
実行時にアルゴリズムを動的に変更することができる。
```js
// Implementation example of the Strategy Pattern
class Context {
constructor(strategy) {
this.strategy = strategy;
}
executeStrategy() {
this.strategy.execute();
}
}
class ConcreteStrategyA {
execute() {
console.log("Strategy A is executed.");
}
}
class ConcreteStrategyB {
execute() {
console.log("Strategy B is executed.");
}
}
const contextA = new Context(new ConcreteStrategyA());
contextA.executeStrategy(); // Output: "Strategy A is executed."
const contextB = new Context(new ConcreteStrategyB());
contextB.executeStrategy(); // Output: "Strategy B is executed."
```
## Command Pattern
どのような状況で使うのかがわかっていない。
Invokerは実行するコマンド(単一)を随時変更することができる?
```js
// Implementation
class Receiver {
execute() {
console.log("Receiver executes the command.");
}
}
class Command {
constructor(receiver) {
this.receiver = receiver;
}
execute() {
this.receiver.execute();
}
}
class Invoker {
setCommand(command) {
this.command = command;
}
executeCommand() {
this.command.execute();
}
}
const receiver = new Receiver();
const command = new Command(receiver);
const invoker = new Invoker();
invoker.setCommand(command);
invoker.executeCommand(); // Output: "Receiver executes the command."
```
## Iterator Pattern
どのような状況で使うのかがわかっていない。
Set で済みそうな気もしてるけど果たして…。
```js
// Implementation
class Collection {
constructor() {
this.items = [];
}
addItem(item) {
this.items.push(item);
}
createIterator() {}
}
// Concrete Aggregate
class ConcreteCollection extends Collection {
createIterator() {
return new ConcreteIterator(this);
}
}
// Iterator
class Iterator {
constructor(collection) {
this.collection = collection;
this.index = 0;
}
hasNext() {}
next() {}
}
// Concrete Iterator
class ConcreteIterator extends Iterator {
hasNext() {
return this.index < this.collection.items.length;
}
next() {
return this.collection.items[this.index++];
}
}
// Usage
const collection = new ConcreteCollection();
collection.addItem("Item 1");
collection.addItem("Item 2");
collection.addItem("Item 3");
const iterator = collection.createIterator();
while (iterator.hasNext()) {
console.log(iterator.next());
}
```
## Mediator Pattern
オブジェクト同士がメッセージをやり取りするときに使える。
```js
// Implementation
class Mediator {
constructor() {
this.colleague1 = null;
this.colleague2 = null;
}
setColleague1(colleague) {
this.colleague1 = colleague;
}
setColleague2(colleague) {
this.colleague2 = colleague;
}
notifyColleague1(message) {
this.colleague1.receive(message);
}
notifyColleague2(message) {
this.colleague2.receive(message);
}
}
class Colleague {
constructor(mediator) {
this.mediator = mediator;
}
send(message) {
// Send a message to the mediator
this.mediator.notifyColleague2(message);
}
receive(message) {
console.log(`Received message: ${message}`);
}
}
// Usage
const mediator = new Mediator();
const colleague1 = new Colleague(mediator);
const colleague2 = new Colleague(mediator);
mediator.setColleague1(colleague1);
mediator.setColleague2(colleague2);
colleague1.send("Hello Colleague 2!"); // Output: "Received message: Hello Colleague 2!"
```