简介
设计模式是我们在解决问题的时候针对特定问题给出的简洁而优化的处理方案
在js设计模式中最核心的思想:封装变化
将变与不变分离,确保变化的部分灵活,不变的部分稳定
1.构造器模式
构造器模式就是构造函数,(用于添加多个对象时,可以简化代码,并且赋值到新的变量中)
使用函数分配到内存从而给到新的变量
对代码进行封装,提高代码的复用性
缺点:
对里面的函数也会每次创建新的内存,(使用原型模式可以解决)
写法
function fun (name, age) {
this.name = name
this.age = age
}
let person = new fun('name', 100)
console.log(person) // fun {name: 'name', age: 100}
2.原型模式
原型模式就是把方法存放放在该对象的原型上,从而减少内存,只存放一次,
使用:
let employeel = {
name: 'name',
age: 100
}
function fun (name, age) {
this.name = name
this.age = age
}
fun.prototype.say = function () {
console.log(this.name, this.age);
}
let person = new fun('name', 100)
person.say() // fun {name: 'name', age: 100}
es6中class类就具有构造器模式和原型模式,也是存放一次,改变内容,
// 使用class类 兼顾构造器模式和原型模式 自动把方法挂在到原型上
class fun1 {
constructor(name, age) {
this.name = name
this.age = age
}
}
let new1 = new fun1('name', 100)
console.log(new1); // fun1 {name: 'name', age: 100}
3.工厂模式
是一种创建对象的设计模式,他通过使用工厂来实现对象的创建,而不是直接使用构造函数,可以减少重复的代码,提高代码的可维护性和扩展性
function User (name, age) {
this.name = name;
this.age = age;
}
// 封装工厂
function UserFactory (role) {
switch (role) {
case 'user': return new User('用户', 15); break;
case 'guest': return new User('游客', 18); break;
case 'admin': return new User('管理员', 20); break;
default: return new User('未知', 0); break;
}
}
let suer = UserFactory('user')
console.log(suer);
class 方式
class Admin { constructor(name, age) { this.name = name; this.age = age; } }
// es6的方式
class UserFactorys {
// 静态方法
static create (role) {
switch (role) {
case 'user': return new Admin('用户', 15); break;
case 'guest': return new Admin('游客', 18); break;
case 'admin': return new Admin('管理员', 20); break;
default: return new Admin('未知', 0); break;
}
}
}
let admin = UserFactorys.create('admin')
console.log(admin);
4.抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是 围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
抽象工厂模式并不直接生成实例,而是用于对产品类簇的创建。
我们先创建一个 User 类(超级工厂),里面有两个方法,welcome() 方法用于欢迎某一类人,dataShow() 方法用于打印某一类人(子类重写的方式)。
之后我们创建三个子类 SuperAdmin、Admin、Editor(其他工厂),均继承自 User,它们继承父类的 name 和 welcome() 方法,重写父类的 dataShow() 方法。
class User {
constructor(name, role) {
this.name = name;
this.role = role;
}
welcome () {
console.log(`欢迎${this.name},您的角色是${this.role}`)
}
dataShow () {
throw new Error('抽象方法不能被调用')
}
}
class Admin extends User {
constructor(name) {
super(name, '管理员')
}
dataShow () { console.log('管理员数据展示') }
}
let admin = new Admin('admin')
admin.welcome()
5.建造者模式
建造者模式可以将一个复杂的对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示
使用
class Navbar {
init () {
console.log('创建导航栏=num');
}
getData () {
console.log('获取导航栏数据=num');
return new Promise((resolve, reject) => {
setTimeout
(() => {
console.log('111');
resolve('导航栏数据')
})
})
}
rander () {
console.log('渲染导航栏=num');
}
}
// 建造者
class Creator {
async starBuild (builter) {
await builter.init()
await builter.getData()
await builter.rander();
}
}
const op = new Creator().starBuild(new Navbar())
6.单例模式
单列模式就是:保证一个类仅有一个实例,并有一个访问他的全局访问点
// 单例模式:保证一个类只有一个实例,并提供一个访问它的全局访问点
// 1.使用闭包实现单例模式
let Singleaton = (function () {
let instance = null
function USer (name, age) {
this.name = name
this.age = age
}
return function
(name, age) {
if (!instance) {
instance = new USer(name, age)
}
return instance
}
})()
let user = Singleaton('张三', 18) // 实例化一次
console.log(user) // 张三;
// es6实现单例模式
class Esingleaton {
constructor(name, age) {
if (!Esingleaton.instance) {
this.name = name
this.age = age
Esingleaton.instance = this
}
return Esingleaton.instance
}
}
let es = new Esingleaton('李四', 20) // 实例化一次
let es6 = new Esingleaton('李四1', 200) // 实例化一次
console.log(es === es6) // true;
7.装饰器模式
是一种结构设计模式,用于在不变原有对象的基础上,动态的给对象添加功能或职责
// 装饰器模式:在不改变对象自身的基础上,在程序运行期间给对象动态地添加职责(方法或属性)
Function.prototype.before = function (beforefn) {
let _this = this
return function () {
// 执行前置的函数调用
beforefn.apply(this, arguments)
// 执行原来的函数
return _this.apply(this, arguments)
}
}
Function.prototype.after = function (after) {
let _this = this
return function () {
let result = _this.apply(this, arguments)
// 执行前置的函数调用
after.apply(this, arguments)
// 执行原来的函数
return result
}
}
function test () {
console.log('111111111111');
return 1
}
// test()
let text1 = test.before(function () {
console.log('222222222222');
}).after(function () {
console.log('333333333333');
})
text1()
8.适配器模式
适配器模式是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的另一个接口,从而使原来不兼容的类可以协同工作,适配器的主要工作是将一个了类的接口转换成客户端所期望的接口,以便客户端可以使用这个类
class TentcentMap {
constructor() {
this.show = () => {
console.log('腾讯地图')
}
}
}
class BaiduMap {
display () {
console.log('百度地图')
}
}
// 适配器模式
class TencentAdaater extends TentcentMap {
constructor(map) {
super()
}
display (map) {
this.show()
}
}
function renderMap (map) {
map.display();
}
renderMap(new TencentAdaater());
renderMap(new BaiduMap());
9.策略模式
定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换
let cal = {
'+': (a, b) => a + b,
'-': (a, b) => a - b,
'*': (a, b) => a * b,
'/': (a, b) => a / b,
}
function calButton (num1, num2, operator) {
if (!cal[operator]) {
return '运算符错误'
}
return cal[operator](num1, num2)
}
console.log(calButton(1, 2, '+'))
10.代理模式
JS代理模式是一种结构性设计模式,它允许你在访问对象之前或之后添加额外的逻辑或控制。JS代理模式是面向对象编程范式中的一个关键概念
// 代理模式
class Star {
paly () {
console.log('唱歌');
}
}
class StarProxy {
constructor() {
this.star = new Star()
}
talk (price) {
if (price > 100000) {
this.star.paly()
} else {
console.log('太贵了')
}
}
}
let jr = new StarProxy()
jr.talk(1000000)
jr.talk(10000)
// es6
let star = {
name: "timo",
workPice: 10000
}
let proxy = new Proxy(star, {
get (sarget, key) {
console.log('访问了');
if (key === 'workPice') {
console.log('访问了');
}
return sarget[key]
},
set (staget, key, value) {
if (key === 'workPice') {
console.log('设置了');
if (value > 10000) {
console.log('可以合作');
} else {
console.log('太贵了');
}
}
}
})
11.观察者模式
是一种行为设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 观察者模式
class subject {
constructor() {
this.observers = []
}
add (obsever) {
this.observers.push(obsever)
}
notify () {
this.observers.forEach(obsever => {
console.log(obsever);
obsever.update()
})
}
remove
(obsever) {
this.observers = this.observers.filter(item => item !== obsever)
}
}
class obsever {
constructor(name) {
this.name = name
}
update () {
console.log('更新了', this.name);
}
}
let Subject = new subject()
Subject.add(new obsever('123'))
Subject.add(new obsever('456'))
console.log(Subject.notify());
</script>
</body>
</html>
12.发布订阅模式
也被称为观察者模式,他定义对象的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知
// publish 发布
// subscribe 订阅
let PubSub = {
list: [],
publish () {
this.list.forEach(cb => cb())
},
subscribe (cb) {
this.list.push(cb)
}
}
function testA () {
console.log('testA')
}
function testB () {
console.log('testB')
}
function testA () {
console.log('testA')
}
function testB () {
console.log('testB')
}
PubSub.subscribe(testA)
PubSub.subscribe(testB)
PubSub.publish()
// publish 发布
// subscribe 订阅
let PubSub1 = {
list: [],
message: {},
publish (type, data) {
if (!this.message[type]) return
this.message[type].forEach(cb => cb(data))
},
subscribe (type, cb) {
if (!this.message[type]) {
this.message[type] = [cb]
} else {
this.message[type].push(cb)
}
},
unsubscrube (type, cb) {
if (!this.message[type]) return
if (!cb) {
this.message[type] && (this.message[type].length = 0)
} else {
this.message[type] = this.message[type].filter(item => item !== cb)
}
}
}
function testA1 (data) {
console.log('testA', data)
}
function testB1 (data) {
console.log('testB', data)
}
PubSub1.subscribe('A', testA1)
PubSub1.subscribe('B', testB1)
PubSub1.publish('A', 1)
PubSub1.publish('B', 2)
13.摸块模式
模块化模式最初被定义为在传统软件工程种为提供私有和共有封装的一种方法
// 模块模式
class Persom {
#name = '踩踩踩事实上'
}
console.log(new Persom
.#name
);
const obj = (function () {
let count = 0
return {
incese () {
return ++count
},
devrse () {
return --count
}
}
})
14.桥接模式
是一种结构型设计模式,它允许我们将对象组合成树形结构,一次处理整个树形结构中的所有对象。组合模式允许客户端代码以一致的方式处理单个对象和复合对象,从而使代码更加灵活和可扩展
let Folder = function (folder) {
this.folder = folder
this.list = [] //保存子文件夹或者文件
Folder.prototype.add = function (file) {
this.list.push(file)
}
Folder.prototype.scan = function () {
console.log('开始扫描文件夹' + this.folder)
for (let i = 0; i < this.list.length; i++) {
this.list[i].scan()
}
}
}
let File = function (file) {
this.file = file
File.prototype.add = function () {
throw new Error('文件下不能添加文件')
}
File.prototype.scan = function () {
console.log('开始扫描文件跟' + this.file)
}
}
let rootFoler = new Folder('root')
let folder1 = new Folder('folder1')
let folder2 = new Folder('folder2')
let file1 = new Folder('file1')
let file2 = new Folder('file2')
// 文件
let html4 = new File('html4')
let html5 = new File('html5')
let css = new File('css')
let js = new File('js')
folder1.add(html4)
folder1.add(html5)
folder2.add(css)
folder2.add(js)
rootFoler.add(folder1)
rootFoler.add(folder2)
folder1.add(file1)
rootFoler.scan()
15.组合模式
一种结构型设计模式,它允许我们将对象组合成树形结构,一次处理整个树形结构中的所有对象。组合模式允许客户端代码以一致的方式处理单个对象和复合对象,从而使代码更加灵活和可扩展
let Folder = function (folder) {
this.folder = folder
this.list = [] //保存子文件夹或者文件
Folder.prototype.add = function (file) {
this.list.push(file)
}
Folder.prototype.scan = function () {
console.log('开始扫描文件夹' + this.folder)
for (let i = 0; i < this.list.length; i++) {
this.list[i].scan()
}
}
}
let File = function (file) {
this.file = file
File.prototype.add = function () {
throw new Error('文件下不能添加文件')
}
File.prototype.scan = function () {
console.log('开始扫描文件跟' + this.file)
}
}
let rootFoler = new Folder('root')
let folder1 = new Folder('folder1')
let folder2 = new Folder('folder2')
let file1 = new Folder('file1')
let file2 = new Folder('file2')
// 文件
let html4 = new File('html4')
let html5 = new File('html5')
let css = new File('css')
let js = new File('js')
folder1.add(html4)
folder1.add(html5)
folder2.add(css)
folder2.add(js)
rootFoler.add(folder1)
rootFoler.add(folder2)
folder1.add(file1)
rootFoler.scan()
16.命令模式
提供了一种将命令封装为对象的方式,从而允许我们将请求与实际执行该请求的操作对象解耦,这种模式可以在不同的场景中使用,例如实现撤销/重做操作、队列任务等,本文我们将讲解命令设计模式在JS中的使用
class Receiver {
// 接受类
excute () {
// 执行
console.log("接收者执行命令");
}
}
class Command {
constructor(receiver) {
this.receiver = receiver
}
// 命令类
execute () {
// 执行命令
console.log("命令执行,处理订单");
}
}
class Invoker {
// 发布类
constructor(command) {
this.command = command
}
execute () {
console.log("发布者执行命令");
// 执行命令
this.command.execute()
}
}
const orer = new Command(new Receiver())
const invoker = new Invoker(orer)
invoker.execute()
17.模板方法摸块
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
let Container = function (params) {
let F = function () { }
F.prototype.init = function () {
this.step1();
this.step2();
let list = params.getData()
this.step3(list);
}
F.prototype.step1 = params.getData || function () {
return new Error('子类没有实现step1方法')
},
F.prototype.step2 = function () {
console.log('step2');
},
F.prototype.step3 = function (list) {
console.log('step3', list);
}
return F
}
let Container1 = Container({
getData: function () {
console.log('子类实现step1');
return [1, 2, 3]
}
})
new Container1().init()
18.迭代器模式
提供了一种方法顺序一个聚合对象各个元素,而又不暴露该对象内部表示
let kerwinEach = function (arr, callback) {
for (let i = 0; i < arr.length; i++) {
callback(arr[i], i, arr)
}
}
kerwinEach([1, 2, 3, 4, 5], function (item, index, arr) {
console.log(item, index, arr)
})
// es6
let obj = {
code: 200,
list: [1, 2, 3, 4, 5],
[Symbol.iterator]: function () {
let index = 0
return {
next: () => {
if (index < this.list.length) {
return {
value: this.list[index++],
done: false
}
} else {
return {
value: undefined,
done: true
}
}
}
}
}
}
let it = obj[Symbol.iterator]()
console.log(it.next())
console.log(it.next())
19.职责链模式
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止
<input type="text" name="" id="input">
<button id="btn">注册</button>
<script>
btn.onclick = function () {
var input = document.getElementById('input')
var value = input.value
if (value.length.length == 0) {
console.log('不能为空');
} else {
if (Number.isNaN(Number(value))) {
console.log('必须是数字');
} else {
if (value.length < 6) {
console.log('长度不能小于6');
}
}
}
}
// 职责链模式
var Chain = function (fn) {
this.fn = fn
this.next = null
}
// 封装成函数
function checkEmpty () {
if (value.length.length == 0) {
console.log('不能为空');
}
}
function checkNumber () {
if (Number.isNaN(Number(value))) {
console.log('必须是数字');
}
}
function checkLehgth () {
if (value.length < 6) {
console.log('长度不能小于6');
}
}
class Chain {
constructor(fn) {
this.fn = fn
this.next = null
}
}