浅谈四种设计模式

在这里讲述代理模式、观察者模式、装饰器、职责链模式。

1、代理模式

  • 首先通过一小段代码来理解一下什么是代理模式
  • 男孩要去给女孩送礼物,但是不好意思直接送,所以就出现了一个代理对象去帮男孩给女孩送礼物。
    代码示例
// 代理模式的简单实现
        // 声明对象
        var Girl = function (name) {
            this.name = name;
        }

        var Boy = function (girl) {
            this.girl = girl;
            this.sendGift = function (gift) {
                console.log("hi," + this.girl.name + ",送你礼物:" + gift);
            }
        }
        // 代理对象

        var ProxyObj = function (girl) {
            this.girl = girl;
            this.sendGift = function (gift) {
                (new Boy(this.girl)).sendGift(gift);
            }
        }

        var girl = new Girl("小芳");
        var proxyObj = new ProxyObj(girl);
        proxyObj.sendGift("999朵玫瑰")
  • 用代理模式可以实现图片懒加载,在一个网页中如果展示的图片很大,展现在页面的时间会比较长,这时候可以使用一张小图片暂时代替大图片展现在页面,等到大图片加载完成之后再将小图片换成大图片。
    具体代码实现
 // 使用代理模式可以实现图片懒加载
        var myImage = (function () {
            var imgNode = document.createElement('img');
            document.body.appendChild(imgNode);
            var img = new Image(); // 代理对象,先展示等待的小图片,接着负责拉取真是图片
            img.onload = function () { // 当真实图片加载完成后触发
                imgNode.src = this.src;
            }
            return {
                setSrc: function (src) {
                    // 先展示等待的小图片
                    imgNode.src = "https://img.lanrentuku.com/img/allimg/1212/5-121204193R0.gif";
                    // 为了明显的看到效果,这里设置成异步,延迟3秒
                    var timer = setTimeout(() => {
                        img.src = src; // 把真实图片地址给代理对象,等到代理对象的图片加载完成之后,将图片给imgNode,让其展示真正的图片
                        clearTimeout(timer)
                    }, 3000)

                }
            }
        })()
  • 结果展示(这里好像展示不了动图,只有分成两张图片了)
    刚开始展示的是小图片
    在这里插入图片描述
    大图片加载完成之后展示大图片
    在这里插入图片描述

2、观察者模式

  • 观察者模式
    • 示例:用户先订阅商品,当商家发布商品之后,用户就可以获得商品。
      具体实现如下
 		// 发布者
        var shopObj = {}
        // 商品列表
        shopObj.list = []
        // 订阅
        shopObj.listen = function (key, fn) {
            if (!this.list[key]) {
                this.list[key] = []
            }
            this.list[key].push(fn);
        }
        // 发布消息
        shopObj.publish = function (key) {
            var fns = this.list[key];
            for (let i = 0, fn; fn = fns[i]; i++) {
                // 执行订阅的fn
                fn.apply(this, arguments);
            }
        }
        // 添加订阅
        shopObj.listen("huawei", function (brand, model) {
            console.log(brand, model);
        })
        shopObj.listen('apple', function (brand, model) {
            console.log(brand, model);
        })
        // 商家发布消息
        shopObj.publish("huawei", 'p30');
        shopObj.publish('apple', 'iphone 11')
  • 将代码重构
 // 代码重构
        var event = {
            list: [],
            listen: function (key, fn) {
                if (!this.list[key]) {
                    this.list[key] = []
                }
                this.list[key].push(fn);
            },
            publish: function (key) {
                var fns = this.list[key];
                for (let i = 0, fn; fn = fns[i]; i++) {
                    fn.apply(this, arguments)
                }
            }
        }
        // 观察者对象初始化
        var initEvent = function (obj) {
            // for(let i in event) {
            //     obj[i] = event[i];
            // }
            // 也可以使用这种方法复制对象
            Object.assign(obj, event)
        }
        // 发布者
        var shopObj2 = {}
        initEvent(shopObj2);
        // 添加订阅
        shopObj2.listen("huawei", function (brand, model) {
            console.log(brand, model);
        })
        shopObj2.listen('apple', function (brand, model) {
            console.log(brand, model);
        })
        // 商家发布消息
        shopObj2.publish("huawei", 'p30');
        shopObj2.publish('apple', 'iphone 11')
  • 结果展示
    在这里插入图片描述

3、装饰器

  • 其实就是相当与Java中的注解。
  • 通过一个简单的示例来了解一些装饰器
    代码如下
  // 装饰器的实现
        class Circle {
            draw() { //行为
                console.log("画一个圆");
            }
        }
        // 使用装饰器添加边框
        class Decorator {
            constructor(circle) {
                this.circle = circle;
            }
            draw() {
                this.circle.draw();
                this.setBorderCircle(this.circle); //装饰品方法
            }
            setBorderCircle(circle) {
                console.log("绘制边框");
            }
        }

        var circle = new Circle();
        new Decorator(circle).draw();
  • 以注解的形式简单实现以下装饰器
    具体代码
// 装饰器----注解形式
class Boy {
    @run 
    speak() {
        console.log("我能唱歌");
    }
}

function run(target,key,descriptor) {
    // target表示Boy对象,key=被修饰的方法名,descriptor是speak方法描述对象 
    console.log(target,key,descriptor);
    console.log("我能跑步");
}

var boy = new Boy()
boy.speak()
  • 注意:如果直接这样子写的话,会直接报错,要通过安装第三方插件的形式将代码转换为es5的形式。
  • 分别下载插件 babel-cli 、babel-preset-env 、babel-plugin-transform-decorators-legacy
  • 添加.babelrc文件
    内容如下
{
    "presets": ["env"],
    "plugins": ["transform-decorators-legacy"]
}
  • 还需要在package.json文件中添加运行的语句
 "scripts": {
    "build": "babel src/Boy.js -o build/Boy.js", //指定具体打包的文件
    "build-dir": "babel src -d build" // 打包src下的所有文件
  },
  • 在命令窗口中运行: npm run build,就能得到打包好的文件,然后直接运行打包好的文件,可以得到如下结果:
    在这里插入图片描述
  • 装饰器的应用
    代码如下
class Math {
    @log(100) // 给方法添加日志输出功能 传递参数
    add(a,b) {
        return a + b;
    }
}

function log(num) {
    var _num = num || 0;
    return function(target,name,descriptor) {
        var oldValue = descriptor.value; //add方法
        // 重写
        descriptor.value = function(...arg){
            arg[0] += _num;
            arg[1] += _num;
            console.log(`调用${name}参数:`,arg);
            return oldValue.apply(target,arg)
        }
        return descriptor
    }
}

var math = new Math();
var res = math.add(1,2);
console.log(res);
  • 结果如下
    在这里插入图片描述

4、职责链模式

  • 简单来说就是将任务传递下去,就好像是“击鼓传花”的游戏。
  • 通过一个简单的示例了解一下职责链模式
  • 例子:充值抽奖
    充值达到500元可抽100元,达到20元可抽20元,否则无奖
    使用职责链实现 问题:如果再添加一个抽奖活动,则代码又需要重新修改,不符合 开闭原则(对修改关闭,对扩展开放)。
  • 具体代码
function order500(orderType,isPay,count) {
           if(orderType == 1 && isPay) {
               console.log("您中奖了100元");
           }else{
               order200(orderType,isPay,count)
           }
       }
       function order200(orderType,isPay,count) {
           if(orderType == 2 && isPay) {
               console.log("您中奖了20元");
           }else{
               orderNormal(orderType,isPay,count)
           }
       }
       function orderNormal(orderType,isPay,count) {
          if(count > 0) {
              console.log("您已抽到10元");
          }else{
              console.log("谢谢参与");
          }
       }
  • 通过职责链模式将代码再次重构一下
    具体代码
// 使用职责链重构代码
       function order500(orderType,isPay,count) {
           if(orderType == 1 && isPay) {
               console.log("您中奖了100元");
           }else{
              return "nextSuccessor"
           }
       }
       function order200(orderType,isPay,count) {
           if(orderType == 2 && isPay) {
               console.log("您中奖了20元");
           }else{
               return "nextSuccessor"
           }
       }
       function orderNormal(orderType,isPay,count) {
          if(count > 0) {
              console.log("您已抽到10元");
          }else{
              console.log("谢谢参与");
          }
       }
       // 职责链关系对象
       function Chain(fn) {
           this.fn = fn;
           this.successor = null;
       }
       Chain.prototype.setNextSuccessor = function(successor) {
           this.successor = successor;
       }
       Chain.prototype.passRequest = function() {
           var ret = this.fn.apply(this,arguments);
           if(ret === "nextSuccessor") {
               this.successor.passRequest.apply(this.successor,arguments)
           }
       }
       // 实例化职责链
       var chainOrder500 = new Chain(order500);
       var chainOrder200 = new Chain(order200);
       var chainOrderNormal = new Chain(orderNormal);
       // 把链子串起来
       chainOrder500.setNextSuccessor(chainOrder200);
       chainOrder200.setNextSuccessor(chainOrderNormal);

       chainOrder500.passRequest(1,true,500)
       chainOrder200.passRequest(2,true,100)
  • 在控制台上输出的结果为
    在这里插入图片描述

总结

这四种模式是在B站学习的过程中看到的,不是特别理解,所以在此做一下笔记。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值