本篇内容适合对设计模式有些了解,但想更进一步了解设计模式在实际场景应用的读者。
一、设计模式原则
-
单一职责原则:一个函数只做一件事,如果功能过于复杂就拆分开
-
开发/封闭原则:对扩展开放,对修改封闭;增加需求时,扩展新代码,而非修改已有代码
-
里氏替换原则:子类能覆盖父类
-
接口隔离原则:保持接口的单一独立
-
依赖倒转原则:面向接口编程,依赖于抽象而不依赖于具体;使用方只关注接口而不关注具体类的实现
二、创建型设计模式
1、工厂模式
实质:一个工厂对象负责创建其他对象,而具体的创建逻辑由子类决定
应用:根据参数,调用对应的插件
js
// 统计插件
class AnalyticsPlugin {
init() {
console.log("初始化统计插件");
}
}
// 日志插件
class LoggerPlugin {
init() {
console.log("初始化日志插件");
}
}
// 工厂对象
class PluginFactory {
createPlugin(types) {
types.forEach((type) => {
switch (type) {
case "analytics":
this.init(AnalyticsPlugin);
break;
case "logger":
this.init(LoggerPlugin);
break;
default:
throw new Error("Invalid plugin type.");
}
});
}
//初始化插件
init(Plugin) {
const plugin = new Plugin();
plugin.init();
}
}
// 使用示例
const pluginFactory = new PluginFactory();
//初始化统计插件,初始化日志插件
pluginFactory.createPlugin(["analytics", "logger"]);
2、单例模式
实质:一个类只有一个实例
应用:全局状态管理器vuex和redux,单例弹窗
js
// 实现单体模式弹窗
var createWindow = (function () {
var div;
return function () {
if (!div) {
div = document.createElement("div");
div.innerHTML = "我是弹窗内容";
div.style.display = "none";
document.body.appendChild(div);
}
return div;
};
})();
document.getElementById("btn").onclick = function () {
var win = createWindow();
win.style.display = "block";
};
3、原型模式
实质:通过复制现有对象来创建新对象
应用:JavaScript的原型
js
function Shape() {
this.name = "Shape";
}
Shape.prototype.draw = function () {
console.log(this.name + " is drawing...");
};
function Rectangle() {
Shape.call(this);
this.name = "Rectangle";
}
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
function Circle() {
Shape.call(this);
this.name = "Circle";
}
Circle.prototype = Object.create(Shape.prototype);
Circle.prototype.constructor = Circle;
// 测试Rectangle和Circle的继承关系
let rectangle = new Rectangle();
let circle = new Circle();
rectangle.draw(); // 输出 "Rectangle is drawing..."
circle.draw(); // 输出 "Circle is drawing..."
三、结构型设计模式
1、适配器模式
实质:将一个类的接口转换成客户端所期望的另一个接口。
应用:vue的computed,react的useMemo
computed:
js
<template>
<div>
{{ message }}
{{ reversedMessage }}
</div>
</template>
<script setup lang="ts">
import { computed, ref } from "vue";
const message = ref("hello vue");
const reversedMessage = computed(() =>
message.value.split("").reverse().join("")
);
</script>
useMemo:
js
import { useMemo, useState } from "react";
function App() {
const [message] = useState("hello react");
const reversedMessage = useMemo(
() => message.split("").reverse().join(""),
[message]
);
return (
<div className="App">
{message}
{reversedMessage}
</div>
);
}
export default App;
2、装饰器模式
实质:动态地给对象添加一些额外的功能
应用:React的高阶组件(HOC)
js
import { useState, useEffect } from "react";
//高阶组件
function withLoading(WrappedComponent) {
return function ({ isLoading, ...props }) {
if (isLoading) {
return <div>Loading...</div>;
} else {
return <WrappedComponent {...props} />;
}
};
}
//业务组件
function DataList({ data }) {
return (
<ul>
{data.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
const DataListWithLoading = withLoading(DataList);
function App() {
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
setData([1, 2, 3]);
setIsLoading(false);
}, 2000);
}, []);
return (
<div>
<h1>Data List</h1>
<DataListWithLoading data={data} isLoading={isLoading} />
</div>
);
}
export default App;
3、代理模式
实质:创建一个代理对象来控制对另一个对象的访问
应用:使用ES6的Proxy
js
let obj = {
a: 1,
b: 2,
};
let proxy = new Proxy(obj, {
get(target, key, receiver) {
console.log("监听get");
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
console.log("触发set");
Reflect.set(target, key, value, receiver);
},
deleteProperty(target, key) {
console.log("监听删除");
Reflect.deleteProperty(target, key);
//如果抛出错误或者返回false,当前属性就无法被delete命令删除
return true;
},
has(target, key) {
console.log("监听has");
return Reflect.has(target, key);
},
});
proxy.a; //监听get
proxy.a = 4; //触发set
delete proxy.b; //监听删除
"a" in proxy; //监听has
四、行为型设计模式
1、观察者模式
实质:一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知
应用:比起观察者模式,更常用发布-订阅模式实现跨组件通信
js
class Observer {
constructor() {
this.all = new Map();
}
on(type, handler) {
const handlers = this.all.get(type);
if (handlers) {
handlers.push(handler);
} else {
this.all.set(type, [handler]);
}
}
off(type, handler) {
const handlers = this.all.get(type);
if (handlers) {
if (handler) {
const i = handlers.indexOf(handler);
if (i > -1) {
handlers.splice(i, 1);
}
} else {
this.all.set(type, []);
}
}
}
emit(type, args) {
const handlers = this.all.get(type);
if (handlers) {
handlers.forEach((handler) => handler(args));
}
}
}
2、策略模式
实质:根据不同参数可以命中不同的策略
应用:在对象中定义一系列算法,随取随用
js
//表单校验
var strategies = {
/* 不为空 */
isNonEmpty: function (value, errorMsg) {
if (value === "") {
return errorMsg;
}
},
/* 限制最小长度 */
minLength: function (value, length, errorMsg) {
if (value.length < length) {
return errorMsg;
}
},
/* 手机号码格式 */
isMobile: function (value, errorMsg) {
let rule = /^1[3|5|8][0-9]{9}$/;
if (!rule.test(value)) {
return errorMsg;
}
},
};
3、模板方法模式
实质:父类定义公共的行为和逻辑,在子类中实现具体的细节
应用:抽象类
js
//抽象类
abstract class DefinePlugin {
public name: string;
constructor(name: string) {
this.name = name;
}
//抽象方法
abstract monitor(): void;
}
//子类
class BehaviorPlugin extends DefinePlugin {
constructor() {
super("behavior");
}
//定义具体的实现
monitor(): void {
["click"].forEach(function (eventType) {
document.addEventListener(
eventType,
(e) => {
//处理点击事件
},
true
);
});
}
}
4、责任链模式
实质:允许对象在链上依次处理请求
应用:数据验证
js
/* 验证url */
class UrlValidator {
setNext(validator) {
this.nextValidator = validator;
}
validate(data) {
if (!data.url) {
console.error("url不存在");
return false;
} else if (this.nextValidator) {
return this.nextValidator.validate(data);
} else {
return true;
}
}
}
/* 验证缓存数量 */
class NumberValidator {
setNext(validator) {
this.nextValidator = validator;
}
validate(data) {
if (!data.count) {
console.error("请输入数量");
return false;
} else if (data.count && data.count < 0) {
console.error("请输入非负数");
} else if (this.nextValidator) {
return this.nextValidator.validate(data);
} else {
return true;
}
}
}
/* 责任链模式 */
const urlValidator = new UrlValidator();
const maxValidator = new NumberValidator();
/* 指定节点在责任链中的顺序 */
urlValidator.setNext(maxValidator);
urlValidator.validate({
url: "1",
count: -1, //请输入非负数
});
5、中介者模式
实质:对象和对象之间借助第三方中介者进行通信
应用:聊天室
js
/* 中介者 */
class Mediator {
constructor() {
this.list = [];
}
add(data) {
this.list.push(data);
}
/* 广播事件 */
broadcast(source, message) {
this.list.filter((o) => o !== source).forEach((o) => o.receive(message));
}
}
const mediator = new Mediator();
class User {
constructor() {
this.mediator = mediator;
this.mediator.add(this);
}
send(message) {
this.mediator.broadcast(this, message);
}
receive(message) {
console.log(`Received message: ${message}`);
}
}
// 使用中介者模式进行组件之间的通信
const user1 = new User();
const user2 = new User();
user1.send("Hello from User 1");
user2.send("Hi from User 2");
这里只是展示中介者示例,实际项目中,可借助WebSocket的广播事件
五、结尾
如果这篇文章对你有帮助,欢迎点赞收藏!!!