什么是设计模式?
在软件开发程中通用的解决方案。
目前有23中设计模式
设计原则:单一职责原则(SRP)、开放封闭原则(OCP)、最少知识原则(LKP)
1、代理模式
场景1:花店替人送花
//声明女同学
var Girl = function(name){
this.name = name;
}
//声明男同学
var Boy = function(girl){
//女同学
this.girl = girl;
//送花 行为
this.sendGirl = function(gift){
console.log('hi' + this.girl.name + ",送你一个小礼物" + gift);
}
}
//代理对象 花店员工
var proxyObj = function(girl){
this.girl = girl;
this.sendGirl = function(gift){
(new Boy(this.girl).sendGirl(gift)); //替人送花
}
}
//调用
var girl = new Girl("小红");
var proxy = new proxyObj(girl);
proxy.sendGirl("999朵玫瑰");
场景2:图片懒加载
- 普通写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片懒加载</title>
</head>
<body>
<script>
//解决图片懒加载
window.onload = function(){
var myImage = (function(){
var imgNode = document.createElement("img");
document.body.appendChild(imgNode);
var img = new Image(); //代理对象 先展示等待图片 接着负责拉取真实图片
img.onload = function(){
setTimeout(()=>{
imgNode.src = this.src;
},2000)
}
return {
setSrc: function(src){
//先展示等待小图片
imgNode.src = "./loading.gif";
img.src = src;
}
}
})()
//把真实图片给到myImage对象
myImage.setSrc("./mei.jpg"); //真实图片地址
}
</script>
</body>
</html>
- 使用更高级代理模式写法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//解决图片懒加载
window.onload = function(){
//使用代理模式重构懒加载
//真实对象 闭包
var myImage = (function(){
var imgNode = document.createElement("img");
document.body.appendChild(imgNode);
return {
setSrc: function(src){
imgNode.src = src;
}
}
})()
//代理对象
var proxyImage = (function(){
var img = new Image();
img.onload = function(){
setTimeout(()=>{
myImage.setSrc(this.src);
},2000)
}
return {
setSrc: function(src){
myImage.setSrc("./loading.gif");
img.src=src;
}
}
})()
//调用
proxyImage.setSrc("./mei.jpg");
}
</script>
</body>
</html>
2、观察者模式
也叫发布订阅模式,例如:点餐,网上点外卖。
当我们去买鞋,发现看中的款式已经售罄了,售货员告诉你不久后这个款式会进货,到时候打电话通知你。于是你留了个电话,离开了商场,当下周某个时候进货了,售货员拿出小本本,给所有关注这个款式的人打电话。
- 场景代码:双11购买商品
//观察者设计模式
var event = {
list:[], //商品列表
//订阅方法
listen: function(key, fn){
if(!this.list[key]){
this.list[key] = [];
}
shopObj.list[key].push(fn)
},
//发布消息方法
publish:function(){
var key = arguments[0];
var fns = this.list[key];
for(var i=0, fn; fn = fns[i++];){
//执行订阅的fn arguments js内置对象 存储所有实参
fn.apply(this, arguments);
}
}
}
//初始化
var initEvent = function(obj){
for(var i in event){
obj[i] = event[i];
}
}
//发布者
var shopObj = {};
initEvent(shopObj);
//A添加订阅
shopObj.listen("huawei",function(brand, model){
console.log("A订阅:"+ brand +" "+ model);
})
//B添加订阅
shopObj.listen("apple",function(brand, model){
console.log("B订阅:"+brand+" "+ model);
})
//双11,商家发布消息
shopObj.publish("huawei", "P40");
shopObj.publish("apple", "iphone 14");
3、装饰器模式
给新房子装修
允许向一个对象添加新的功能,但不改变原有对象。
- decorator.js
//使用装饰器给add方法添加日志 并且传入参数。
//运行此文件包需安装babel插件:babel-cli、babel-preset-env、babel-plugin-transform-decorators-legacy,将es6转为es5才能执行
class Math {
@log(100)
add(a, b){
return a + b;
}
}
function log(num){
return function log(target, name, decorators){
//三个参数说明:target 是Math对象、 name 是 "add" 名称 、 decorators 是add方法
var oldValue = decorators.value; //add方法
var _num = num;
//重构add方法
decorators.value = function(...arg){
console.log(`调用 ${name} 方法, 参数为:`, arg);
arg[0] += _num; //让第一个参数增加100
return oldValue.apply(target, arg);
}
return decorators;
}
}
var math = new Math();
var result = math.add(1,2);
console.log(result);
//运行结果:
//调用 add 方法, 参数为: [ 1, 2 ]
//103
- .babelrc
{
"presets": ["env"],
"plugins": ["transform-decorators-legacy"]
}
- package.json
{
"scripts": {
"build": "babel src/decorator.js -o build/math.js",
"build-dir": "babel src -d build"
},
"dependencies": {
"babel-cli": "^6.26.0",
"babel-plugin-transform-decorators-legacy": "^1.3.5",
"babel-preset-env": "^1.7.0"
}
}
4、职责链
场景: 击鼓传花、充值抽奖
- 案例场景:跟领导请假
//领导基类
var Leader = function(){
this.nextLeader = null;
}
Leader.prototype.setNext = function(next){
this.nextLeader = next;
return next; //返回可链式调用setNext
}
/* 小组领导 */
var GroupLeader = new Leader();
GroupLeader.handle = function(duration){
if (duration <= 0.5) {
console.log('小组领导经过一番心理斗争:批准了')
} else{
this.nextLeader && this.nextLeader.handle(duration)
}
}
/* 部门领导 */
var DepartmentLeader = new Leader()
DepartmentLeader.handle = function(duration) {
if (duration <= 1) {
console.log('部门领导经过一番心理斗争:批准了')
} else{
this.nextLeader.handle(duration)
}
}
/* 总经理 */
var GeneralLeader = new Leader();
GeneralLeader.handle = function (duration) {
if (duration <= 2) {
console.log('总经理经过一番心理斗争:批准了')
} else{
console.log('总经理:不准请这么长的假')
}
}
GroupLeader
.setNext(DepartmentLeader) // 设置小组领导的下一个职责节点为部门领导
.setNext(GeneralLeader) // 设置部门领导的下一个职责节点为总经理
GroupLeader.handle(0.5) // 小组领导经过一番心理斗争:批准了
GroupLeader.handle(1) // 部门领导经过一番心理斗争:批准了
GroupLeader.handle(2) // 总经理经过一番心理斗争:批准了
GroupLeader.handle(3) // 总经理:不准请这么长的假
5、单例模式
Vuex 源码中的store的实现就是单例模式。所以每个 Vue 实例只会拥有一个全局的 Store
-
优点: 节约资源,保证访问的一致性。
-
缺点: 扩展性不友好,因为单例模式一般自行实例化,没有接口。
6、工厂模式
根据不同的参数,返回不同类的实例。
标签:function,src,img,babel,前端,修炼,var,girl,设计模式 From: https://www.cnblogs.com/sgs123/p/16949730.html