前端设计模式介绍及案例(单例模式、代理模式、工厂模式、装饰者模式、观察者模式)

概要

本文主要介绍了前端设计模式的定义、分类以及常用设计模式的具体案例。

前言

使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

分类

一、创建型模式-研究高效的创建对象

单例模式

抽象工厂模式

建造者模式

工厂模式

原型模式

二、结构型模式-设计对象的结构和关系

适配器模式

桥接模式

装饰模式

组合模式

外观模式

享元模式

代理模式

三、行为型模式-设计对象的行为

模板方法模式

命令模式

迭代器模式

观察者模式

中介者模式

备忘录模式

解释器模式

状态模式

策略模式

职责链模式

访问者模式

开发时的流程

优先降低复杂度,尽量降低耦合度

1.利用单一职责原则,开闭原则,里氏代换原则降低复杂度。

2.通过迪米特法则减少耦合度

3.通过依赖倒置原则消除可以没有的耦合

定义及案例

1.单例模式:

​ 一个类仅有一个实例

javascript 复制代码
<div class="toast">
        <button id="alertBtn">弹窗</button>
        <button id="alertBtn1">弹窗1</button>
        <button id="alertBtn2">弹窗2</button>
        <div>我是弹窗</div>
    </div>
    <script>
        // var alert = (function(){
        //     var div = document.createElement('div');
        //     div.innerHTML = '我是弹窗';
        //     div.style.display = 'none';
        //     document.body.appendChild(div)
        //     return div
        // })()
        
        // document.getElementById('alertBtn').onclick = function(){
        //     alert.style.display = 'block'
        // }
        // var createAlert = function(){
        //     var div = document.createElement('div');
        //     div.innerHTML = '我是弹窗1'
        //     div.style.display = 'none'
        //     document.body.appendChild(div)
        //     return div
        // }
        // document.getElementById('alertBtn1').onclick = function(){
        //     var alertLayer = createAlert();
        //     alertLayer.style.display = 'block'
        // }
        
        var createAlert1 = (function(){
            var div;
            return function(){
                if(!div){
                    div = document.createElement('div');
                    div.innerHTML = '我是弹窗2'
                    div.style.display = 'none'
                    document.body.appendChild(div)
                }
                return div
            }
            
        })()

        var createIframe = (function(){
            var iframe;
            return function(){
                if(!iframe){
                    iframe = document.createElement('div');
                    iframe.innerHTML = '我是iframe'
                    document.body.appendChild(iframe)
                }
                return iframe
            }
        })()
        var getSingle = function( fn ){
            var result;
            if(!result){
                result = fn.apply(this, arguments)
            }
            return function(){
                return result
            }
        }

        var createAlert3 = function(){
            var div = document.createElement('div');
            div.innerHTML = '我是弹窗3'
            div.style.display = 'none'
            document.body.appendChild(div)
            return div
        }

        var createSingleAlert = getSingle(createAlert3)

        // document.getElementById('alertBtn2').onclick = function(){
        //     var alertLayer = createSingleAlert();
        //     alertLayer.style.display = 'block'
        // }

        var createIframe1 = function(){
            var iframe = document.createElement('iframe')
            document.body.appendChild(iframe);
            return iframe
        }
        
        var createIframe2 = getSingle(createIframe1)

        document.getElementById('alertBtn2').onclick = function(){
            var iframe1111 = createIframe2();
            iframe1111.src = 'http://www.baidu.com'
        }



    </script>
2.代理模式:

​ 虚拟代理:虚拟代理是把一些开销很大的对象,延迟到真正需要它的时候才去创建执行=====图片加载,文件上传

​ 安全/保护代理:控制真实对象的访问权限=====登录操作后才能看全功能,前端校验

​ 远程代理(一个对象将不同空间的对象进行局部代理)=====监控多个对象的状态,总机监控分店

​ 智能代理(调用对象代理处理另外一些事情如垃圾回收机制增加额外的服务)=====提供额外的其他服务火车站代售处

javascript 复制代码
    <script>
        // 代理模式
        // 定义:为一个对象提供一个代用品或占位符,以便控制它的访问。
        // 关键点:当客户不方便直接访问一个对象或者不满足需求的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象。
        // 替身对象对请求做出一些处理之后,再把请求转交给本体对象(女神)
        // 租房者  中介代理4500  房东3500
        // 代理模式好处有点事什么。
        // 第一回 第一个人上
        // 
        // var Flower = function(name) {
        //     var flowers = {
        //         flowers: name
        //     }
        //     return flowers
        // }

        // var dengGe = {
        //     sendFlower: function(target) {
        //         var flowers = new Flower('向日葵')
        //         target.receiveFlower(flowers.flowers)
        //     }
        // }

        // var goddess1 = {
        //     receiveFlower: function(flower) {
        //         console.log('收到:' + flower + ',你是个好人')
        //     }
        // }

        // dengGe.sendFlower(goddess1)
        // 第二回,第二个人上
        // var Flower = function(name) {
        //     var flowers = {
        //         flowers: name
        //     }
        //     return flowers
        // }

        // var dengGe = {
        //     sendFlower: function(target) {
        //         var flowers = new Flower('向日葵')
        //         target.receiveFlower(flowers.flowers)
        //     }
        // }

        // var chengGe = {
        //     receiveFlower: function(flower) {
        //         goddess2.receiveFlower(flower)
        //     }
        // }

        // var goddess2 = {
        //     receiveFlower: function(flower) {
        //         console.log('女神收到:' + flower + ',你是个好人')
        //     }
        // }

        // dengGe.sendFlower(chengGe)
        // 第三回,众人出主意
        var Flower = function(name) {
            var flowers = {
                flowers: name
            }
            return flowers
        }
        var dengGe = {
            sendFlower: function(target) {
                var flowers = new Flower('向日葵')
                target.receiveFlower(flowers.flowers)
            }
        }

        var chengGe = {
            receiveFlower: function(flower) {
                // 监听心情好的时候
                goddess3.listenGoodMood(function() {
                    goddess3.receiveFlower(flower)
                })
            }
        }

        var goddess3 = {
                receiveFlower: function(flower) {
                    console.log('女神收到:' + flower)
                },
                listenGoodMood: function(fn) {
                    setTimeout(function() {
                        fn()
                    }, 200000)
                }
            }
            //一天一束  有需求的时候一束 解约成本
            // 开销很大的对象,等待真正需要的时候再去创建
            // 代理另一个优点:保护的作用
            // 登录的时候,
            // 代理模式:保护,节约成本。
            // 代理模式的本质:保护和中介
        dengGe.sendFlower(chengGe)
    </script>
3.工厂模式:

​ 高效的创建对象

​ 定义:工厂模式定义创建对象的接口,但是让子类去真正的实例化。也就是工厂方法将类的实例化延迟到子类

javascript 复制代码
    <!-- 统一建造 -->
    <!-- 简单工厂  抽象工厂  工厂模式-->
    <!-- 造车 -->
    <script>
        // 定义车工场
        function CarFactory() {}
        // BBA
        CarFactory.BMW = function() {
            this.name = "宝马"
        }
        CarFactory.Benz = function() {
            this.name = "奔驰"
        }
        CarFactory.Audi = function() {
            this.name = '奥迪'
        }
        CarFactory.prototype.drive = function() {
            return '该批次的' + this.name + '添加了自动驾驶功能'
        }
        CarFactory.create = function(carName) {
            if (typeof(CarFactory[carName]) !== 'function') {
                console.log('无法建造' + carName)
                return false
            }
            if (typeof(CarFactory[carName].prototype.drive !== 'function')) {
                CarFactory[carName].prototype = new CarFactory();
            }
            var newCar = new CarFactory[carName]();
            return newCar
        }
        var car = CarFactory.create('BMW')
        console.log(car.drive())
            // 创建的时候使用,用来统一建造
    </script>

4.工厂方法模式(抽象工厂)

​ 代码比简单工厂模式复杂了,引入了抽象层,还有子工厂,这会增加代码的复杂度和理解难度。

​ 但是相比于简单工厂模式,代码的维护性和扩展性提高了,新增产品时,只需要增加对应的产品类和产品工厂类,不需要修改到抽象工厂类和其他子工厂。

​ 更加符合面向对象的开放封闭原则

5.装饰者模式

​ 定义:在不改变元对象的基础上,通过对其进行包装拓展(添加属性方法)

​ 装饰者(decorator)模式能够在不改变对象自身的基础上在程序运行期间给对像动态的添加职责。

​ 与继承相比,装饰者是一种更轻便灵活的做法。

​ 可以当脚本运行时,在子类中增加行为会影响原有类所有的实例,而装饰者却不然。取而代之的是它能给不同对象各自添加新行为

​ 实现:构造函数需要一个装饰资源池,提供相应的装饰方法,提供添加装饰方法的方法。

javascript 复制代码
    <script>
        // 定义:在不改变远对象的基础上,通过对其进行包装和拓展(添加属性和方法)使原有的对象可以满足用户更复杂的需求。
        // 买房子,给你交付毛坯房,功能性不强,外观,卧室,客厅,洗手间。。。。
        // var house = {
        //     name: '房子',
        //     xxx: 'k',
        //     yyy: ''
        // }
        // Macbook 没有光驱,内存8G,16G。保险
        function Macbook() {
            this.cost = function() {
                return 1000
            }
        }
        // 内存
        function Memory(macbook) {
            this.cost = function() {
                return macbook.cost() + 100
            }
        }
        // 蓝光驱动器
        function BlurayDrive(macbook) {
            this.cost = function() {
                return macbook.cost() + 300
            }
        }
        // 保险
        function Insurance(macbook) {
            this.cost = function() {
                return macbook.cost() + 200
            }
        }

        var myMacBook = new Macbook();
        var myMacBook1 = new Memory(new Macbook())
        console.log('我花费了:' + myMacBook1.cost())
    </script>
6.观察者模式

​ 定义:观察者模式,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。

​ 事实上,只要你曾经在DOM节点上绑定过事件函数,那么你就曾经使用过观察者模式了!

javascript 复制代码
    <!-- 发布订阅模式 -->
    <!-- 设立一个观察哨,监视你的一举一动,根据你的一举一动,来做出相应的反应 -->
    <!-- 发布消息,订阅消息,退订消息  公众号 发布一篇文章,订阅公众,取消关注 -->
    <!-- A 对象 -> B对象 -->
    <!-- 多线程 -->
    <!-- 汇率计算  1 人民币兑美元  日元  韩元 -->
    <script>
        var observer = (function() {
            var _message = {};
            return {
                // 订阅信息
                regist: function(type, fn) {
                    if (typeof _message[type] === 'undefined') {
                        _message[type] = [fn]
                    } else {
                        _message[type].push(fn)
                    }
                },
                //发布信息
                fire: function(type, args) {
                    // 如果消息没有被注册,则返回
                    if (!_message[type]) {
                        return
                    }
                    // 定义一下消息信息
                    var events = {
                        type: type,
                        args: args || {}
                    }

                    var len = _message[type].length;
                    for (var i = 0; i < len; i++) {
                        _message[type][i].call(this, events)
                    }
                },
                // 移除
                remove: function(type, fn) {
                    if (_message[type] instanceof Array) {
                        var i = _message[type].length - 1;
                        for (i; i >= 0; i--) {
                            _message[type][i] === fn && _message[type].splice(i, 1)
                        }
                    }
                }
            }
        })()
        observer.regist('test', function(e) {
            console.log(e.type, e.args.msg)
        })
        observer.fire('test', {
            msg: '发布信息1111'
        })
    </script>
相关推荐
2401_8976056513 分钟前
星动纪元ERA-42:端到端原生机器人大模型的里程碑式突破
前端·人工智能·机器人
祁许33 分钟前
【Vue】在Vue3中使用Echarts的示例 两种方法
前端·vue.js·typescript·vue·echarts
illus10n_CHOU44 分钟前
【项目总结】易到家家政服务平台 —— 派单调度(7)
java·spring boot·后端·学习·设计模式
码上飞扬1 小时前
Vue 3 30天精进之旅:Day 21 - 项目实践:打造功能完备的Todo应用
前端·javascript·vue.js
大梦一厂1 小时前
Vue的数据为什么频繁变化但只会更新一次
前端·javascript·vue.js
打野赵怀真1 小时前
DOM0、DOM2、DOM3事件处理方式的区别是什么?
前端·javascript
pink大呲花1 小时前
利用ES6 Set去重
开发语言·javascript·es6
bin91531 小时前
DeepSeek 助力 Vue 开发:打造丝滑的进度条
前端·javascript·vue.js·deepseek
轻口味2 小时前
Vue.js 与第三方插件的集成
前端·javascript·vue.js
斯~内克2 小时前
现代前端开发的演进与未来趋势:从工具革新到技术突破
前端