§ 创建型模式
1. 工厂模式 (Factory Pattern)
// 工厂函数创建不同类型的产品
class ProductA {
getName() {
return 'Product A';
}
}
class ProductB {
getName() {
return 'Product B';
}
}
function createProduct(type) {
if (type === 'A') {
return new ProductA();
} else if (type === 'B') {
return new ProductB();
}
}
const product1 = createProduct('A');
console.log(product1.getName()); // 输出: Product A
特性:通过工厂函数创建对象,隐藏具体实现细节,客户端只需知道接口。
应用场景:动态创建不同类型对象,如表单控件生成、日志记录器。
-
优点:解耦客户端与具体产品类,符合单一职责原则
-
缺点:添加新产品需要修改工厂类,违反开闭原则
1. Q: 工厂模式与直接使用new创建对象有什么区别?
A: 工厂模式将对象创建逻辑集中管理,客户端无需知道具体类名,符合"开闭原则"(对扩展开放,对修改关闭),当需要添加新产品时只需扩展工厂类而不用修改客户端代码。
2. Q: 什么时候应该使用简单工厂而不是抽象工厂?
A: 当产品种类较少且不会频繁变化时使用简单工厂;当产品族需要一起创建或有复杂层次结构时使用抽象工厂。
2. 单例模式 (Singleton Pattern)
const Singleton = (function() {
let instance;
function createInstance() {
return {
name: 'Singleton Instance',
getName() {
return this.name;
}
};
}
return {
getInstance() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();
console.log(instance1 === instance2); // 输出: true
特性:确保类只有一个实例,并提供全局访问点。
应用场景:全局状态管理、配置对象、数据库连接池。
-
优点:严格控制实例访问,节省内存
-
缺点:难以测试(全局状态),违反单一职责原则
3. 建造者模式(Builder Pattern)
class CarBuilder {
constructor() {
this.car = {};
}
setModel(model) {
this.car.model = model;
return this;
}
setColor(color) {
this.car.color = color;
return this;
}
build() {
return this.car;
}
}
const car = new CarBuilder()
.setModel('Tesla')
.setColor('Red')
.build();
console.log(car); // 输出: { model: 'Tesla', color: 'Red' }
特性:分步骤构建复杂对象,允许客户端灵活配置。
应用场景:分步创建复杂对象,如文件上传配置、UI 组件构建。
4. 原型模式(Prototype Pattern)
const userPrototype = {
name: 'Default User',
sayHello() {
console.log(`Hello, I'm ${this.name}`);
},
clone() {
return Object.create(this);
}
};
const user1 = userPrototype.clone();
user1.name = 'Alice';
user1.sayHello(); // 输出: Hello, I'm Alice
const user2 = userPrototype.clone();
user2.name = 'Bob';
user2.sayHello(); // 输出: Hello, I'm Bob
特性:通过克隆现有对象创建新实例,避免重复初始化。
应用场景:对象初始化成本高时,如复杂 DOM 节点、游戏角色。
§ 结构型模式
1. 适配器模式(Adapter Pattern)
// 旧接口
class OldMap {
display() {
console.log('Displaying old map');
}
}
// 新接口
class NewMap {
show() {
console.log('Displaying new map');
}
}
// 适配器
class MapAdapter {
constructor(map) {
this.map = map;
}
display() {
if (this.map.show) {
this.map.show();
}
}
}
const oldMap = new OldMap();
const newMap = new NewMap();
const adaptedMap = new MapAdapter(newMap);
oldMap.display(); // 输出: Displaying old map
adaptedMap.display(); // 输出: Displaying new map
特性:使不兼容接口能够一起工作
应用场景:集成第三方库、新旧接口兼容
2. 装饰器模式(Decorator Pattern)
class Coffee {
cost() {
return 5;
}
}
class CoffeeDecorator {
constructor(coffee) {
this.coffee = coffee;
}
cost() {
return this.coffee.cost();
}
}
class MilkDecorator extends CoffeeDecorator {
cost() {
return super.cost() + 2;
}
}
class SugarDecorator extends CoffeeDecorator {
cost() {
return super.cost() + 1;
}
}
let coffee = new Coffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
console.log(coffee.cost()); // 输出: 8
特性:动态为对象添加功能,不修改原对象。
应用场景:扩展对象功能,如日志记录、权限校验。
-
优点:比继承更灵活,符合开闭原则
-
缺点:多层装饰会增加复杂性,调试困难
3. 代理模式(Proxy Pattern)
// 真实对象
class RealSubject {
request() {
console.log('RealSubject: Handling request.');
return 'real-data';
}
}
// 代理对象
class ProxySubject {
constructor(realSubject) {
this.realSubject = realSubject;
}
request() {
if (this.checkAccess()) {
console.log('Proxy: Pre-processing request.');
const result = this.realSubject.request();
console.log('Proxy: Post-processing request.');
return result;
}
}
checkAccess() {
console.log('Proxy: Checking access permissions.');
return true;
}
}
const realSubject = new RealSubject();
const proxy = new ProxySubject(realSubject);
console.log(proxy.request());
/* 输出:
Proxy: Checking access permissions.
Proxy: Pre-processing request.
RealSubject: Handling request.
Proxy: Post-processing request.
real-data
*/
特性:为对象提供代理,控制访问或延迟初始化。
应用场景:延迟加载、访问控制。
1. Q: 装饰器模式与代理模式有什么区别?
A: 关键区别在于目的:
装饰器:动态添加功能(透明增强)
代理:控制访问(可能限制功能)
装饰器通常透明地增强对象,而代理可能完全改变行为
4. 外观模式(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();
/* 输出:
Subsystem A operation
Subsystem B operation
*/
特性:为复杂子系统提供简化接口。
应用场景:简化复杂库或模块的调用。
§ 行为型模式
1. 观察者模式(Observer Pattern)
class Weather {
constructor() {
this.observers = [];
}
attach(observer) {
this.observers.push(observer);
}
notify(temp) {
this.observers.forEach(observer => observer.update(temp));
}
setTemp(temp) {
this.notify(temp);
}
}
class Observer {
constructor(name) {
this.name = name;
}
update(temp) {
console.log(`${this.name} received temperature: ${temp}°C`);
}
}
const weather = new Weather();
const observer1 = new Observer('Observer 1');
const observer2 = new Observer('Observer 2');
weather.attach(observer1);
weather.attach(observer2);
weather.setTemp(25);
/* 输出:
Observer 1 received temperature: 25°C
Observer 2 received temperature: 25°C
*/
特性:定义一对多依赖关系,对象状态变化时通知所有观察者。
应用场景:事件处理、数据绑定。
2. 策略模式(Strategy Pattern)
class SortContext {
constructor(strategy) {
this.strategy = strategy;
}
setStrategy(strategy) {
this.strategy = strategy;
}
execute(data) {
return this.strategy.sort(data);
}
}
class AscendingSort {
sort(data) {
return [...data].sort((a, b) => a - b);
}
}
class DescendingSort {
sort(data) {
return [...data].sort((a, b) => b - a);
}
}
const data = [3, 1, 4, 1, 5, 9, 2, 6];
const ascendingSort = new AscendingSort();
const descendingSort = new DescendingSort();
const context = new SortContext(ascendingSort);
console.log(context.execute(data)); // 输出: [1, 1, 2, 3, 4, 5, 6, 9]
context.setStrategy(descendingSort);
console.log(context.execute(data)); // 输出: [9, 6, 5, 4, 3, 2, 1, 1]
特性:封装一系列算法,客户端可动态切换。
应用场景:动态选择算法,如排序、表单验证规则。
3. 命令模式(Command Pattern)
class Light {
turnOn() {
console.log('Light is on');
}
turnOff() {
console.log('Light is off');
}
}
class Command {
constructor(receiver) {
this.receiver = receiver;
}
execute() {}
}
class TurnOnCommand extends Command {
execute() {
this.receiver.turnOn();
}
}
class TurnOffCommand extends Command {
execute() {
this.receiver.turnOff();
}
}
class RemoteControl {
constructor() {
this.command = null;
}
setCommand(command) {
this.command = command;
}
pressButton() {
this.command.execute();
}
}
const light = new Light();
const turnOnCommand = new TurnOnCommand(light);
const turnOffCommand = new TurnOffCommand(light);
const remote = new RemoteControl();
remote.setCommand(turnOnCommand);
remote.pressButton(); // 输出: Light is on
remote.setCommand(turnOffCommand);
remote.pressButton(); // 输出: Light is off
特性:将请求封装为对象,支持撤销、重做或队列操作。
应用场景:实现撤销/重做功能、任务队列。
4. 状态模式(State Pattern)
class Order {
constructor() {
this.state = new PendingState(this);
}
setState(state) {
this.state = state;
}
request() {
this.state.handle();
}
}
class PendingState {
constructor(order) {
this.order = order;
}
handle() {
console.log('Order is pending');
this.order.setState(new ProcessingState(this.order));
}
}
class ProcessingState {
constructor(order) {
this.order = order;
}
handle() {
console.log('Order is processing');
this.order.setState(new ShippedState(this.order));
}
}
class ShippedState {
constructor(order) {
this.order = order;
}
handle() {
console.log('Order is shipped');
}
}
const order = new Order();
order.request(); // 输出: Order is pending
order.request(); // 输出: Order is processing
order.request(); // 输出: Order is shipped
特性:允许对象根据内部状态改变行为。
应用场景:状态机,如订单状态管理、游戏角色状态切换。
§ 其他常见模式
1. 迭代器模式(Iterator Pattern)
class Iterator {
constructor(data) {
this.data = data;
this.index = 0;
}
next() {
if (this.index < this.data.length) {
return { value: this.data[this.index++], done: false };
} else {
return { done: true };
}
}
}
const data = [1, 2, 3];
const iterator = new Iterator(data);
let result = iterator.next();
while (!result.done) {
console.log(result.value);
result = iterator.next();
}
/* 输出:
1
2
3
*/
特性:提供统一接口遍历集合元素。
应用场景:遍历数组、链表等数据结构。
2. 发布-订阅模式(Pub/Sub Pattern)
class EventBus {
constructor() {
this.events = {};
}
subscribe(event, callback) {
if (!this.events[event]) {
this.events[event] = [];
}
this.events[event].push(callback);
}
publish(event, data) {
if (this.events[event]) {
this.events[event].forEach(callback => callback(data));
}
}
}
const eventBus = new EventBus();
eventBus.subscribe('event1', data => {
console.log('Subscriber 1 received:', data);
});
eventBus.subscribe('event1', data => {
console.log('Subscriber 2 received:', data);
});
eventBus.publish('event1', 'Hello World');
/* 输出:
Subscriber 1 received: Hello World
Subscriber 2 received: Hello World
*/
特性:解耦发布者与订阅者,支持一对多通信。
应用场景:事件总线、消息队列。
3. 模块模式(Module Pattern)
const CounterModule = (function() {
let count = 0;
function increment() {
count++;
}
function getCount() {
return count;
}
return {
increment,
getCount
};
})();
CounterModule.increment();
console.log(CounterModule.getCount()); // 输出: 1
console.log(CounterModule.count); // 输出: undefined (私有变量不可访问)
特性:封装私有变量和方法,暴露公共接口。
应用场景:代码组织、避免全局污染。
§ 高阶函数
1. 什么是高阶函数?
高阶函数(Higher-Order Function)是指满足以下任一条件的函数:
1. 接受一个或多个函数作为参数
2. 返回一个函数作为结果
在编程中,高阶函数是将函数视为"一等公民"(first-class citizen)的语言特性体现,意味着函数可以像其他数据类型一样被传递和使用。
2. 高阶函数的特点
1. 函数作为参数:能够接收其他函数作为输入
2. 函数作为返回值:可以生成并返回新的函数
3. 抽象行为:能够抽象和封装常见的行为模式
4. 组合性:可以通过组合简单函数构建复杂功能
5. 延迟执行:返回的函数可以在需要时才执行
3. 高阶函数的用途
1. 抽象与代码复用
// 不使用高阶函数
const arr1 = [1, 2, 3].map(x => x * 2);
const arr2 = [1, 2, 3].map(x => x * 3);
// 使用高阶函数
function multiplyBy(factor) {
return x => x * factor;
}
const arr1 = [1, 2, 3].map(multiplyBy(2));
const arr2 = [1, 2, 3].map(multiplyBy(3));
2. 回调机制
// 事件处理
button.addEventListener('click', () => {
console.log('Button clicked!');
});
// 异步操作
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data));
3. 函数组合与管道
// 组合两个函数
const compose = (f, g) => x => f(g(x));
const toUpperCase = x => x.toUpperCase();
const exclaim = x => `${x}!`;
const shout = compose(exclaim, toUpperCase);
console.log(shout('hello')); // 输出: "HELLO!"
4. 创建装饰器/中间件
// 日志装饰器
function withLogging(fn) {
return (...args) => {
console.log(`Calling with args: ${args}`);
const result = fn(...args);
console.log(`Result: ${result}`);
return result;
};
}
const add = (a, b) => a + b;
const loggedAdd = withLogging(add);
loggedAdd(2, 3); // 输出调用和结果信息
5. 柯里化与部分应用
// 柯里化函数
const curry = fn => {
const arity = fn.length;
return function $curry(...args) {
if (args.length < arity) {
return $curry.bind(null, ...args);
}
return fn.apply(null, args);
};
};
const add = curry((a, b) => a + b);
const add2 = add(2);
console.log(add2(3)); // 5
4. 常见的高阶函数示例
数组方法:map
, filter
, reduce
, sort
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(n => n * 2); // [2, 4, 6, 8]
const evens = numbers.filter(n => n % 2 === 0); // [2, 4]
函数绑定:bind
const greet = function(greeting, name) {
return `${greeting}, ${name}!`;
};
const sayHello = greet.bind(null, 'Hello');
sayHello('Alice'); // "Hello, Alice!"
延迟执行:
function lazyEvaluate(fn) {
return function() {
return fn.apply(this, arguments);
};
}
5. 高阶函数的优势
1. 提高代码可读性:通过命名操作意图而非具体实现
2. 减少重复代码:抽象通用模式
3. 增强灵活性:行为可以通过参数动态配置
4. 支持函数式编程范式:如纯函数、不可变性等
5. 便于测试和维护:小的、可组合的函数单元
高阶函数是现代编程语言中强大的工具,尤其在JavaScript、Python、Haskell等语言中广泛应用,是函数式编程的核心概念之一。
§ 柯里化函数
1. 什么是柯里化函数?
柯里化(Currying)是一种将多参数函数转换为一系列单参数函数的技术。它得名于数学家Haskell Curry,核心思想是:一个接收多个参数的函数可以转换为接收单一参数的函数序列,每次调用返回一个新函数,直到所有参数都被提供,最终返回结果。
// 普通函数
function add(a, b, c) {
return a + b + c;
}
// 柯里化版本
function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
// 使用方式
add(1, 2, 3); // 6
curriedAdd(1)(2)(3); // 6
2. 柯里化函数的特点
1. 参数分解:将多参数函数分解为单参数函数链
2. 延迟执行:在收集到足够参数前不会执行,返回新函数
3. 函数组合:便于创建可组合的函数管道
4. 闭包利用:每个返回的函数都闭包保存了之前传入的参数
5. 部分应用:可以提前固定部分参数,生成更专用的函数
3. 柯里化函数的特性
1. 参数记忆性
const add = a => b => a + b;
const add5 = add(5); // 记住第一个参数5
add5(3); // 8
2. 动态生成函数
const greet = greeting => name => `${greeting}, ${name}!`;
const sayHello = greet('Hello');
const sayHi = greet('Hi');
sayHello('Alice'); // "Hello, Alice!"
sayHi('Bob'); // "Hi, Bob!"
3. 自动柯里化
可以通过工具函数实现自动柯里化:
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
};
}
};
}
const curriedAdd = curry((a, b, c) => a + b + c);
curriedAdd(1)(2)(3); // 6
curriedAdd(1, 2)(3); // 6
curriedAdd(1)(2, 3); // 6
4. 柯里化函数的用途
1. 参数复用
// 创建通用的URL构建器
const buildUrl = protocol => domain => path => `${protocol}://${domain}/${path}`;
const buildHttpsUrl = buildUrl('https');
const githubUrl = buildHttpsUrl('github.com');
githubUrl('username/repo'); // "https://github.com/username/repo"
2. 延迟执行/按需计算
// 日志函数
const logger = level => message => timestamp =>
`[${timestamp}] [${level}] ${message}`;
const errorLogger = logger('ERROR');
const errorMessage = errorLogger('Database connection failed');
errorMessage(new Date().toISOString());
3. 函数组合
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);
const toUpper = str => str.toUpperCase();
const exclaim = str => `${str}!`;
const shout = compose(exclaim, toUpper);
shout('hello'); // "HELLO!"
4. 事件处理
// 事件监听器工厂
const createEventListener = eventType => element => handler => {
element.addEventListener(eventType, handler);
return () => element.removeEventListener(eventType, handler);
};
const createClickHandler = createEventListener('click');
const createButtonClick = createClickHandler(document.getElementById('myBtn'));
const unsubscribe = createButtonClick(e => console.log('Clicked!'));
5. 配置预设
// API请求构建器
const createRequest = baseUrl => headers => method => endpoint => data => {
return fetch(`${baseUrl}/${endpoint}`, {
method,
headers,
body: JSON.stringify(data)
});
};
const apiRequest = createRequest('https://api.example.com')({ 'Content-Type': 'application/json' });
const getUsers = apiRequest('GET')('users');
const createUser = apiRequest('POST')('users');
5. 柯里化的优势
1. 代码复用:通过部分应用减少重复代码
2. 关注点分离:将参数获取与函数执行分离
3. 灵活性:动态生成具有预设参数的函数
4. 可读性:函数调用链更清晰地表达数据处理流程
5. 函数纯度:更容易保持函数纯净(无副作用)
6. 柯里化的局限性
1. 性能开销:嵌套函数调用可能带来轻微性能损失
2. 调试难度:调用栈可能变得更深更复杂
3. 学习曲线:对初学者可能不太直观
4. 过度使用:不是所有场景都适合柯里化
7. 实际应用场景
1. 函数式编程库:Lodash/fp、Ramda等
2. React高阶组件:参数化组件生成器
3. Redux中间件:如redux-thunk的action creators
4. Express中间件:配置预设的处理函数
5. 测试工具:创建特定的测试用例生成器