创建型设计模式(Creational Patterns)
1. 单例模式
确保一个类只有一个实例,并提供一个全局访问点。
示例 1:全局状态管理
// store.js
let instance = null;
class Store {
constructor() {
if (instance) return instance;
this.state = {};
instance = this;
}
getState() {
return this.state;
}
setState(newState) {
this.state = { ...this.state, ...newState };
}
}
const store = new Store();
export default store;
示例 2:配置管理器
class Config {
constructor() {
if (Config.instance) return Config.instance;
this.config = {};
Config.instance = this;
}
set(key, value) {
this.config[key] = value;
}
get(key) {
return this.config[key];
}
}
export default new Config();
2. 工厂模式
定义一个用于创建对象的接口,让子类决定实例化哪一个类。
示例 1:组件工厂
function componentFactory(type) {
switch (type) {
case "button":
return <button>Click</button>;
case "input":
return <input />;
default:
return <div>Unknown</div>;
}
}
示例 2:图表工厂
function createChart(type) {
switch (type) {
case "bar":
return new BarChart();
case "line":
return new LineChart();
default:
throw new Error("Unknown chart type");
}
}
3. 抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
示例 1:主题切换
class LightThemeFactory {
createButton() {
return <button className="light">Light Button</button>;
}
}
class DarkThemeFactory {
createButton() {
return <button className="dark">Dark Button</button>;
}
}
示例 2:跨平台组件
class WebUIFactory {
createModal() {
return <div className="web-modal">Web Modal</div>;
}
}
class MobileUIFactory {
createModal() {
return <div className="mobile-modal">Mobile Modal</div>;
}
}
4. 建造者模式
将一个复杂对象的构建与其表示分离,使同样的构建过程可以创建不同的表示。
示例 1:表单构建器
class FormBuilder {
constructor() {
this.form = [];
}
addInput(name) {
this.form.push(`<input name="${name}" />`);
return this;
}
addButton(label) {
this.form.push(`<button>${label}</button>`);
return this;
}
build() {
return this.form.join("");
}
}
示例 2:HTML 元素构建器
class HtmlBuilder {
constructor(tag) {
this.tag = tag;
this.attrs = {};
this.children = [];
}
setAttribute(key, value) {
this.attrs[key] = value;
return this;
}
appendChild(child) {
this.children.push(child);
return this;
}
build() {
const attrs = Object.entries(this.attrs)
.map(([k, v]) => `${k}="${v}"`)
.join(" ");
const children = this.children.join("");
return `<${this.tag} ${attrs}>${children}</${this.tag}>`;
}
}
5. 原型模式
用原型实例指定创建对象的种类,并通过复制这些原型创建新的对象。
示例 1:表单模板复制
const formTemplate = {
fields: ["name", "email"],
validations: true,
clone() {
return JSON.parse(JSON.stringify(this));
},
};
const newForm = formTemplate.clone();
示例 2:组件配置复制
const buttonPrototype = {
type: "button",
style: { color: "blue" },
onClick: () => alert("clicked"),
clone() {
return { ...this };
},
};
const newButton = buttonPrototype.clone();
结构型设计模式(Structural Patterns)
1. 适配器模式
将一个类的接口转换成客户端期望的接口,使原本由于接口不兼容而不能一起工作的类可以协同工作。
示例 1:封装第三方库接口
// 假设我们使用的是一个老旧图表库 OldChart
class OldChart {
drawPie(data) {
console.log("Drawing pie chart", data);
}
}
// 适配器封装
class ChartAdapter {
constructor() {
this.chart = new OldChart();
}
render(data) {
this.chart.drawPie(data);
}
}
示例 2:统一 API 响应格式
function apiAdapter(response) {
return {
code: response.status,
data: response.payload,
message: response.msg,
};
}
2. 装饰器模式
动态地给对象添加额外的职责,是继承的替代方案。
示例 1:组件功能扩展(高阶组件)
function withLogging(WrappedComponent) {
return function (props) {
console.log("Props:", props);
return <WrappedComponent {...props} />;
};
}
示例 2:ES 装饰器语法(TypeScript)
function readonly(target, name, descriptor) {
descriptor.writable = false;
return descriptor;
}
class Example {
@readonly
name() {
return "Hello";
}
}
3. 外观模式
为子系统中的一组接口提供统一的入口,简化复杂系统的使用。
示例 1:封装本地存储接口
const StorageFacade = {
set(key, value) {
localStorage.setItem(key, JSON.stringify(value));
},
get(key) {
return JSON.parse(localStorage.getItem(key));
},
remove(key) {
localStorage.removeItem(key);
},
};
示例 2:封装网络请求流程
const HttpClient = {
async get(url) {
const res = await fetch(url);
return res.json();
},
async post(url, data) {
const res = await fetch(url, {
method: "POST",
body: JSON.stringify(data),
headers: { "Content-Type": "application/json" },
});
return res.json();
},
};
4. 代理模式
为其他对象提供一种代理以控制对该对象的访问。
示例 1:图片懒加载代理
function lazyLoad(imgElement, realSrc) {
const temp = new Image();
temp.onload = () => {
imgElement.src = realSrc;
};
temp.src = realSrc;
}
示例 2:网络请求缓存代理
const requestProxy = (() => {
const cache = {};
return async function (url) {
if (cache[url]) {
return cache[url];
}
const res = await fetch(url);
const data = await res.json();
cache[url] = data;
return data;
};
})();
5. 组合模式
将对象组合成树形结构以表示“部分-整体”的层次结构。
示例 1:菜单结构渲染
const menu = {
name: "Root",
children: [
{ name: "Item 1" },
{ name: "Item 2", children: [{ name: "Sub Item" }] },
],
};
function renderMenu(item) {
if (!item.children) return `<li>${item.name}</li>`;
return `
<li>${item.name}
<ul>${item.children.map(renderMenu).join("")}</ul>
</li>
`;
}
示例 2:React 树状组件结构
function TreeNode({ node }) {
return (
<li>
{node.label}
{node.children && (
<ul>
{node.children.map((child, i) => (
<TreeNode key={i} node={child} />
))}
</ul>
)}
</li>
);
}
6. 桥接模式
将抽象与实现解耦,使它们可以独立变化。
示例 1:按钮样式与平台分离
class Button {
constructor(theme) {
this.theme = theme;
}
render() {
console.log(`Rendering button in ${this.theme.getColor()}`);
}
}
class DarkTheme {
getColor() {
return "dark";
}
}
class LightTheme {
getColor() {
return "light";
}
}
const darkButton = new Button(new DarkTheme());
darkButton.render(); // Rendering button in dark
示例 2:图表与数据源分离
class Chart {
constructor(dataSource) {
this.dataSource = dataSource;
}
draw() {
const data = this.dataSource.getData();
console.log("Drawing chart with", data);
}
}
class APIDataSource {
getData() {
return [1, 2, 3];
}
}
7. 享元模式
运用共享技术有效支持大量细粒度对象的复用,避免重复创建相同数据。
示例 1:图标复用
class IconFactory {
constructor() {
this.icons = {};
}
getIcon(type) {
if (!this.icons[type]) {
this.icons[type] = new Icon(type);
}
return this.icons[type];
}
}
示例 2:虚拟列表复用 DOM
// 虚拟滚动中只渲染可视区域的 DOM,复用已存在的元素以节省性能
行为型设计模式(Behavioral Patterns)
1. 观察者模式
定义对象间一对多的依赖关系,当一个对象状态发生变化时,所有依赖它的对象都会收到通知并自动更新。
示例 1:事件订阅系统
class EventEmitter {
constructor() {
this.events = {};
}
on(event, listener) {
(this.events[event] ||= []).push(listener);
}
emit(event, ...args) {
(this.events[event] || []).forEach((listener) => listener(...args));
}
}
const emitter = new EventEmitter();
emitter.on("change", (data) => console.log("Changed:", data));
emitter.emit("change", { name: "John" });
示例 2:Vue 响应式系统(简化版)
let activeEffect = null;
function watchEffect(effect) {
activeEffect = effect;
effect();
activeEffect = null;
}
function reactive(obj) {
const deps = new Map();
return new Proxy(obj, {
get(target, key) {
if (activeEffect) {
if (!deps.has(key)) deps.set(key, []);
deps.get(key).push(activeEffect);
}
return target[key];
},
set(target, key, value) {
target[key] = value;
(deps.get(key) || []).forEach((fn) => fn());
return true;
},
});
}
2. 策略模式
定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换。
示例 1:表单校验策略
const strategies = {
isNonEmpty: (val) => val !== "",
isEmail: (val) => /\S+@\S+\.\S+/.test(val),
};
function validate(value, rule) {
return strategies[rule](value);
}
示例 2:不同排序策略切换
const sortByName = (arr) =>
[...arr].sort((a, b) => a.name.localeCompare(b.name));
const sortByAge = (arr) => [...arr].sort((a, b) => a.age - b.age);
function sortUsers(users, strategy) {
return strategy(users);
}
3. 状态模式
允许一个对象在其内部状态发生改变时改变它的行为。
示例 1:按钮状态管理
class Button {
constructor() {
this.state = "normal";
}
click() {
if (this.state === "loading") {
console.log("Please wait...");
} else {
console.log("Button clicked");
}
}
setState(state) {
this.state = state;
}
}
示例 2:表单流程状态控制
class Form {
constructor() {
this.state = "idle";
}
submit() {
if (this.state === "idle") {
this.state = "submitting";
console.log("Submitting...");
}
}
success() {
this.state = "success";
}
fail() {
this.state = "error";
}
}
4. 职责链模式
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。
示例 1:中间件机制(如 Express)
const middlewares = [];
function use(mw) {
middlewares.push(mw);
}
function handleRequest(req, res) {
let i = 0;
function next() {
const mw = middlewares[i++];
if (mw) mw(req, res, next);
}
next();
}
示例 2:前端表单处理链
function createChain(...fns) {
return function (input) {
for (const fn of fns) {
const result = fn(input);
if (!result.success) return result;
}
return { success: true };
};
}
5. 命令模式
将请求封装成对象,从而让你使用不同的请求、队列或日志请求,以及可撤销操作。
示例 1:操作记录撤销
class CommandManager {
constructor() {
this.history = [];
}
execute(command) {
command.execute();
this.history.push(command);
}
undo() {
const command = this.history.pop();
if (command) command.undo();
}
}
class AddCommand {
constructor(target, value) {
this.target = target;
this.value = value;
}
execute() {
this.target.count += this.value;
}
undo() {
this.target.count -= this.value;
}
}
示例 2:UI 操作命令封装
class ShowModalCommand {
execute() {
console.log("Showing modal...");
}
undo() {
console.log("Hiding modal...");
}
}
6. 迭代器模式
提供一种顺序访问集合对象元素而不暴露内部结构的方式。
示例 1:自定义迭代器对象
function createIterator(array) {
let index = 0;
return {
next: () => ({
done: index >= array.length,
value: array[index++],
}),
};
}
示例 2:前端分页组件迭代数据源
class Paginator {
constructor(items, pageSize) {
this.items = items;
this.pageSize = pageSize;
this.page = 0;
}
nextPage() {
this.page++;
return this.items.slice(
this.page * this.pageSize,
(this.page + 1) * this.pageSize
);
}
}
7. 中介者模式
用一个中介对象封装一系列对象交互,减少对象之间的耦合。
示例 1:组件通信中介
class Mediator {
constructor() {
this.components = {};
}
register(name, component) {
this.components[name] = component;
component.setMediator(this);
}
send(message, from, to) {
if (this.components[to]) {
this.components[to].receive(message, from);
}
}
}
示例 2:表单各字段联动更新
// 表单项之间通过 mediator 控制逻辑响应,比如性别切换影响年龄校验逻辑
8. 备忘录模式
在不破坏封装性的前提下捕获对象内部状态,并在以后恢复该状态。
示例 1:表单填写状态保存
class FormMemento {
constructor(state) {
this.state = { ...state };
}
}
class Form {
constructor() {
this.state = {};
this.history = [];
}
setState(newState) {
this.history.push(new FormMemento(this.state));
this.state = { ...this.state, ...newState };
}
undo() {
const memento = this.history.pop();
if (memento) this.state = memento.state;
}
}
示例 2:撤销编辑操作
// 维护状态快照,支持 Ctrl + Z 撤销
9. 解释器模式
给定一种语言,定义其文法的一种表示,并定义一个解释器来解释语言中的句子。
示例 1:简单模版引擎
function interpret(template, context) {
return template.replace(/{{(\w+)}}/g, (_, key) => context[key] || "");
}
示例 2:自定义计算表达式
// 支持输入 "3 + 4 * 2" 的表达式解析与执行
10. 模板方法模式
在父类中定义算法结构,并将具体实现延迟到子类中。
示例 1:组件生命周期钩子调用顺序
class Component {
render() {
this.beforeRender();
console.log("Rendering...");
this.afterRender();
}
beforeRender() {}
afterRender() {}
}
示例 2:请求前后处理模板
class HttpTemplate {
request(url) {
this.before();
fetch(url).then(this.after);
}
before() {
console.log("Loading...");
}
after() {
console.log("Done.");
}
}