JavaScript 设计模式
主要有3种类型的设计模式
- 创建型设计模式:关注对象的创建机制
- 结构型设计模式:关注对象之间关系的方法
- 行为型设计模式:关注对象之间的通信
(创建型)生成器模式
创建复杂对象的构建过程,允许逐步构建对象。
构造函数就是该模式的一种实现方式。
class Person {
constructor(name, age, mother) {
this.name = name;
this.age = age;
this.mother = mother;
}
}
const tim = new Person('Tim', 31, null);
const tina = new Person('Tina', 57, null);
tim.mother = tina;
(创建型)工厂模式
将对象的创建过程封装在工厂类中。
function animalFactory() {
this.createAnimal = function(animalType) {
let animal;
switch(animalType) {
case 'dog':
animal = new Dog();
break;
case 'cat':
animal = new Cat();
break;
default:
break;
}
return animal;
}
}
const Dog = function() {
this.makeSound = () => {
console.log('woof woof!');
}
}
const Cat = function() {
this.makeSound = () => {
console.log('prrr prrr meow!');
}
}
const factory = new animalFactory();
const jojo = factory.createAnimal('dog');
jojo.makeSound();
const smokey = factory.createAnimal('cat');
smokey.makeSound();
(创建型)原型模式
基于现有对象来创建新对象的模式。
const macBook = {
color: 'silver',
turnOn() {
console.log('turning on...');
},
turnOff() {
console.log('turning off...');
}
}
// Proper prototype cloning
const myComputer = Object.create(macBook, { owner: { value: 'Tim'} });
console.log(myComputer.__proto__ === macBook);
macBook.power = 'USB-C';
// The protoype gets the new value for 'power'
console.log(myComputer.power);
(创建型)单例模式
确保一个类只有一个实例,并提供对该类的全局访问点。
const Database = (function () {
let instance;
function createDatabaseInstance() {
return new Object('Database Instance');
}
function getDatabaseInstance() {
if (!instance) {
instance = createDatabaseInstance();
}
return instance;
}
return { getDatabaseInstance }
})();
const databaseInstance1 = Database.getDatabaseInstance();
const databaseInstance2 = Database.getDatabaseInstance();
console.log(databaseInstance1 === databaseInstance2);
(结构型)包装模式
在不改变对象本身的情况下,为对象添加额外的行为或功能。
(结构型)组合模式
将对象组合成树结构以表示部分和整体的关系。
const Node = function(name) {
this.children = [];
this.name = name;
};
Node.prototype = {
add: function(child) {
this.children.push(child);
return this;
}
};
const init = () => {
const tree = new Node('root');
const [left, right] = [new Node("left"), new Node("right")];
const [leftleft, leftright] = [new Node("leftleft"), new Node("leftright")];
const [rightleft, rightright] = [new Node("rightleft"), new Node("rightright")];
tree.add(left).add(right);
left.add(leftleft).add(leftright);
right.add(rightleft).add(rightright);
console.log(tree);
};
init();
(结构型)模块模式
将代码封装在模块中,提供导出接口。
const userApi = () => {
const users = [];
const addUser = (name) => {
users.push(name);
return users[users.length -1];
}
const getAllUsers = () => {
return users;
}
const deleteUser = (name) => {
const userIndex = users.indexOf(name);
if (userIndex < 0) {
throw new Error('User not found');
}
users.splice(userIndex, 1);
}
const updateUser = (name, newName) => {
const userIndex = users.indexOf(name);
if (userIndex < 0) {
throw new Error('User not found');
}
users[userIndex] = newName;
return users[userIndex];
}
return {
add: addUser,
get: getAllUsers,
del: deleteUser,
put: updateUser
}
};
const api = userApi();
api.add('Tim');
api.add('Hina');
api.add('Yasmeen');
api.add('Neeloo');
console.log(api.get());
api.del('Yasmeen');
console.log(api.get());
api.put('Tim', 'Tim Winfred');
console.log(api.get());
(结构型)装饰器模式
动态地为对象添加新功能,而不改变其接口。
const Animal = function(type) {
this.type = type || 'dog';
}
const dog = new Animal('dog');
const cat = new Animal('cat');
dog.bark = function() {
console.log('woof woof!');
return this;
}
cat.meow = function() {
console.log('meow meooooooow!');
return this;
}
dog.bark();
cat.meow();
(结构型)外观模式
为复杂系统提供一个简化的接口,隐藏其复杂性。
import axios from 'axios';
const facade = {
get: function(url, params) {
return axios({
url,
params,
method: 'GET'
}).then(res => res.data);
}
};
function getUsers() {
return facade.get('https://jsonplaceholder.typicode.com/users');
}
function getUserById(id) {
return facade.get('https://jsonplaceholder.typicode.com/users', { id });
}
(结构型)代理模式
控制对其它对象的访问,允许在访问时添加额外的逻辑。
function CryptoCurrencyAPI() {
this.getValue = function(coin) {
console.log(`Calling Crypto API to get ${coin} price...`);
switch(coin.toLowerCase()) {
case 'bitcoin':
return 38000;
case 'ethereum':
return 2775;
case 'dogecoin':
return 0.39;
}
}
}
function CryptoCurrencyAPIProxy() {
this.api = new CryptoCurrencyAPI();
this.cache = {};
this.getValue = function(coin) {
if(!this.cache[coin]) {
console.log(`The value of ${coin} isn't stored in cache...`);
this.cache[coin] = this.api.getValue(coin);
}
return this.cache[coin];
}
}
const proxyAPI = new CryptoCurrencyAPIProxy();
console.log(proxyAPI.getValue('Bitcoin'));
console.log(proxyAPI.getValue('Bitcoin'));
console.log(proxyAPI.getValue('Ethereum'));
console.log(proxyAPI.getValue('Ethereum'));
console.log(proxyAPI.getValue('Dogecoin'));
console.log(proxyAPI.getValue('Dogecoin'));
(行为型)责任链模式
将请求的发送者和接收者解耦,允许多个对象处理请求。
const ATM = function() {
this.withdrawl = function(amount) {
console.log(`Requesting to withdrawl $${amount.toFixed(2)}`);
if (amount % 1 !== 0) {
console.log('Sorry, this ATM can\'t dispense coins. Please request another amount.');
return;
}
const dispenseOutput = {};
// chain or responsibility function
function get(bill) {
dispenseOutput[bill] = Math.floor(amount / bill);
amount -= dispenseOutput[bill] * bill;
return { get };
}
get(100).get(50).get(20).get(10).get(5).get(1);
this.dispense(dispenseOutput);
};
this.dispense = function(bills) {
console.log('--- Dispensing cash ---')
Object.entries(bills).forEach(([key, value]) => {
console.log(`- Dispensing ${value} $${key} bills`);
});
}
};
const myATM = new ATM();
myATM.withdrawl(126.10);
myATM.withdrawl(1287);
myATM.withdrawl(879);
(行为型)命令模式
将请求封装成对象,允许使用不同请求的客户端进行参数化操作。
const calculationMethods = {
add: function(x, y) {
return x + y;
},
subtract: function(x, y) {
return x - y;
},
multiply: function(x, y) {
return x * y;
},
divide: function(x, y) {
return x / y;
}
};
const calculator = {
execute: function(method, num1, num2) {
if (!(method in calculationMethods)) return null;
return calculationMethods[method](num1, num2);
}
};
console.log(calculator.execute('add', 1, 2));
console.log(calculator.execute('subtract', 5, 2));
console.log(calculator.execute('multiply', 11, 2));
console.log(calculator.execute('divide', 10, 2));
console.log(calculator.execute('square root', 20));
(行为型)观察者模式
定义对象之间的一对多依赖关系,其中一个对象的状态更改会导致其所有依赖项被通知和更新。
发布订阅就是该模式的一种实现方式。
function Subject() {
this.observers = [];
}
Subject.prototype = {
subscribe: function(observer) {
this.observers.push(observer);
return this;
},
unsubscribe: function(observer) {
const indexOfObserver = this.observers.indexOf(observer);
if (indexOfObserver > -1) {
this.observers.splice(indexOfObserver, 1);
}
return this;
},
notifyObserver: function(observer) {
const indexOfObserver = this.observers.indexOf(observer);
if (indexOfObserver > -1) {
this.observers[indexOfObserver].notify();
}
return this;
},
notifyAllObservers: function() {
this.observers.forEach(observer => {
observer.notify();
});
return this;
}
}
function Observer(name) {
this.name = name;
}
Observer.prototype = {
notify: function() {
console.log(`Observer ${this.name} has been notified`);
}
};
const subject = new Subject();
const observer1 = new Observer('user001');
const observer2 = new Observer('user002');
const observer3 = new Observer('user003');
const observer4 = new Observer('user004');
const observer5 = new Observer('user005');
subject.subscribe(observer1).subscribe(observer2).subscribe(observer3).subscribe(observer4).subscribe(observer5);
subject.notifyObserver(observer4);
subject.unsubscribe(observer4);
subject.notifyAllObservers();
(行为型)模板方法模式
定义一个算法的骨架,将一些步骤的实现推迟到子类。
class HouseTemplate {
constructor(name, address) {
this.name = name;
this.address = address;
}
buildHouse() {
this.buildFoundation();
this.buildPillars();
this.buildWalls();
this.buildWindows();
console.log(`${ this.name } has been built successfully at ${ this.address }`);
}
buildFoundation() {
console.log('Building foundation...');
}
buildPillars() {
throw new Error('You have to build your own pillars');
}
buildWalls() {
throw new Error('You have to build your own walls');
}
buildWindows() {
console.log('Building windows');
}
}
class WoodenHouse extends HouseTemplate {
constructor(name, address) {
super(name, address);
}
buildPillars() {
console.log('Building pillars for a wooden house');
}
buildWalls() {
console.log('Building walls for a wooden house');
}
}
class BrickHouse extends HouseTemplate {
constructor(name, address) {
super(name, address);
}
buildPillars() {
console.log('Building pillars for a brick house');
}
buildWalls() {
console.log('Building walls for a brick house');
}
}
const woodenHouse = new WoodenHouse('Wooden house', '123 Maple Road');
const brickHouse = new BrickHouse('Brick house', '456 Stone Lane');
woodenHouse.buildHouse();
brickHouse.buildHouse();
(行为型)策略模式
定义一系列算法,将它们封装成独立的对象,使得它们可以互相替换,以改变对象的行为。
function Regal() {
this.getTicketPrice = function(quantity) {
return quantity * 11.99;
}
}
function AMC() {
this.getTicketPrice = function(quantity) {
return quantity * 10.99;
}
}
function Cinemark() {
this.getTicketPrice = function(quantity) {
return quantity * 9.99;
}
}
function TicketPrice() {
this.theaterChain;
this.setTheaterChain = function(chain) {
this.theaterChain = chain;
}
this.calculate = function(quantity) {
return this.theaterChain.getTicketPrice(quantity);
}
}
const regal = new Regal();
const amc = new AMC();
const cinemark = new Cinemark();
const ticketPrice = new TicketPrice();
ticketPrice.setTheaterChain(regal);
console.log(ticketPrice.calculate(2));
ticketPrice.setTheaterChain(amc);
console.log(ticketPrice.calculate(3));
ticketPrice.setTheaterChain(cinemark);
console.log(ticketPrice.calculate(4));