前端常用的设计模式

前言

     设计模式定义:在面向对象软件设计过程中 针对特定问题的简洁而优雅的解决方案。在不同的编程语言中,对设计模式的实现其实是可能会有区别的。

  • 单例模式   
  • 观察者模式
  • 工厂模式
  • 命令模式
  • 职责链模式

   1,单例模式  

       定义:是保证一个类只有一个实例,并且提供一个访问它的全局访问点

       需求:一些对象我们往往只需要一个,比如线程池、全局缓存、浏览器中的window对象、登录浮窗等。

       实现:用一个变量标识当前是否已经为某个类创建过对象,如果是,则在下一次获取这个类的实例时,直接返回之前创建的对象。

       优点:

  • 可以用来划分命名空间,减少全局变量的数量
  • 可以被实例化,且实例化一次,再次实例化生成的也是第一个实例

      基础栗子:

// 单例模式
var Singleton = function(name){
    this.name = name;
    this.instance = null;
};
Singleton.prototype.getName = function(){
    return this.name;
};
// 获取实例对象
Singleton.getInstance = function(name) {
    if(!this.instance) {
        this.instance = new Singleton(name);
    }
    return this.instance;
};
// 测试单例模式的实例
var a = Singleton.getInstance("aa");
var b = Singleton.getInstance("bb");

console.log(a===b)    // true

   实践栗子

(function () {
    //管理单例的逻辑代码,如果没有数据则创建,有数据则返回
   var getSingle = function(fn){ //参数为创建对象的方法
       var result;
       return function(){ //判断是Null或赋值
           return result || (result = fn.apply(this,arguments));
       };
   };
    //创建登录窗口方法
    var createLoginLayer = function(){
        var div = document.createElement('div');
        div.innerHTML = '我是登录浮窗';
        div.style.display = 'none';
        document.body.appendChild(div);
        return div;
    };
    //单例方法
    var createSingleLoginLayer = getSingle(createLoginLayer);

    //使用惰性单例,进行创建
    document.getElementById('loginBtn').onclick = function(){
        var loginLayer = createSingleLoginLayer();
        loginLayer.style.display = 'block';
    };
})()

 

  2,观察者模式

     定义:对象间的一种一对多的依赖关系。

      需求:当一个对象的状态发生变化时,所有依赖于他的对象都将得到通知。

      优点:时间上的解耦,对象之间的解耦。

      实现:

  1. 首先,指定好谁充当发布者;    
  2. 然后,给发布者添加一个缓存列表,用于存放回调函数以便通知订阅者; 
  3. 最后,发布消息的时候,发布者会遍历这个缓存列表,依次触发里面存放的订阅者回调函数。

     基础栗子:

var salesOffices = {};                           // 定义售楼处
salesOffices.clientList = [];                    // 缓存列表,存放订阅者的回调函数
salesOffices.listen = function( fn ){            // 增加订阅者
    this.clientList.push( fn );                  // 订阅的消息添加进缓存列表
};
salesOffices.trigger = function(){               // 发布消息
    for( var i = 0, fn; fn = this.clientList[ i++ ]; ){
        fn.apply( this, arguments );             // arguments 是发布消息时带上的参数
    }
};
//调用
salesOffices.listen( function( price, squareMeter ){//订阅消息
    console.log( '价格= ' + price );
    console.log( 'squareMeter= ' + squareMeter );
});
salesOffices.trigger( 2000000, 88 );                // 输出:200 万,88 平方米

   实践栗子:登录页面登录后,会需要刷新各个模块的信息(头像、nav)这类。

var ObserverEvent = (function () {
        var clientList = [], listen, trigger, remove;
        listen = function (key, fn) {
            if (!clientList[key]) {
                clientList[key] = [];
            }
            clientList[key].push(fn);
        };
        trigger = function () {
            var key = Array.prototype.shift.call(arguments), fns = clientList[key];
            if (!fns || fns.length === 0) {
                return false;
            }
            for (var i = 0, fn; fn = fns[i++];) {
                fn.apply(this, arguments);
            }
        };
        remove = function (key, fn) {
            var fns = clientList[key];
            if (!fns) {
                return false;
            }
            if (!fn) {
                fns && (fns.length = 0);
            } else {
                for (var l = fns.length - 1; l >= 0; l--) {
                    var _fn = fns[l];
                    if (_fn === fn) {
                        fns.splice(l, 1);
                    }
                }
            }
        };
        return {
            listen:listen,
            trigger:trigger,
            remove:remove
        }
    })();
    ObserverEvent.listen('squareMeter88', fn1 = function (price) {
        console.log('价格=' + price);
    });
    ObserverEvent.listen('squareMeter100', function (price) {
        console.log('价格=' + price);
    });
    ObserverEvent.trigger('squareMeter88', 200000);

//刷新模块信息
var header = (function () {
        ObserverEvent.listen('loginSucc', function (data) {
            header.setAvatar(data.avatar);
        });
        return {
            setAvatar: function (data) {
                console.log(data + "设置header成功");
            }
        }
    })();
    var nav = (function () {
        ObserverEvent.listen('loginSucc', function (data) {
            nav.setAvatar(data.avatar)
        });
        return {
            setAvatar: function (data) {
                console.log(data + '设置nav成功');
            }
        }
    })();
    var data = {};
    data.avatar = "参数";
    ObserverEvent.trigger('loginSucc', data);

3,工厂模式:

    定义:将其成员对象的实例化推迟到子类来实现的类。

     需求:创建对象的流程赋值的时候,比如依赖于很多设置文件等 ;处理大量具有相同属性的小对象;注:不能滥用

     优点:不暴露创建对象的具体逻辑,而是将将逻辑封装在一个函数中。     

     分类:简单工厂,工厂方法和抽象工厂。

     实现:

        3.1  简单工厂模式 (创建单一对象,需要的类比较少)

let UserFactory = function (role) {
  function SuperAdmin() {
    this.name = "超级管理员",
    this.viewPage = ['首页', '通讯录', '发现页', '应用数据', '权限管理']
  }
  function Admin() {
    this.name = "管理员",
    this.viewPage = ['首页', '通讯录', '发现页', '应用数据']
  }
  function NormalUser() {
    this.name = '普通用户',
    this.viewPage = ['首页', '通讯录', '发现页']
  }

  switch (role) {
    case 'superAdmin':
      return new SuperAdmin();
      break;
    case 'admin':
      return new Admin();
      break;
    case 'user':
      return new NormalUser();
      break;
    default:
      throw new Error('参数错误, 可选参数:superAdmin、admin、user');
  }
}

 

      3.2  工厂方法模式 (创建多类对象,需要的类比较多)

             为方便后续新增类方便,只需改一处代码,封装了工厂方法而已。并且把类都放在工厂类原型中实现。

 

//安全模式创建的工厂方法函数
let UserFactory = function(role) {
  if(this instanceof UserFactory) {
    var s = new this[role]();
    return s;
  } else {
    return new UserFactory(role);
  }
}

//工厂方法函数的原型中设置所有对象的构造函数
UserFactory.prototype = {
  SuperAdmin: function() {
    this.name = "超级管理员",
    this.viewPage = ['首页', '通讯录', '发现页', '应用数据', '权限管理']
  },
  Admin: function() {
    this.name = "管理员",
    this.viewPage = ['首页', '通讯录', '发现页', '应用数据']
  },
  NormalUser: function() {
    this.name = '普通用户',
    this.viewPage = ['首页', '通讯录', '发现页']
  }
}

//调用
let superAdmin = UserFactory('SuperAdmin');
let admin = UserFactory('Admin') 
let normalUser = UserFactory('NormalUser')

 

     3.3  抽象工厂模式 (创建父类,子类继承父类,具体实现在子类)

         抽象工厂其实是实现子类继承父类的方法,只是一个方法。

         抽象工厂模式一般用在多人协作的超大型项目中,并且严格的要求项目以面向对象的思想进行完成。

// 抽象工厂方法
var VehicleFatory = function(subType, superType) {
    // 判断抽象工厂中是否有该抽象类
    if(typeof VehicleFactory[superType] === 'function') {
        // 缓存类
        function F() {};
        // 继承父类属性和方法
        F.prototype = new VehicleFactory[superType] ();
        // 将子类constructor 指向子类
        subType.constructor = subType;
        // 子类原型继承'父类'
        subType.prototype = new F();
    } else {
        // 不存在该抽象类抛出错误
        throw new Error('未创建该抽象类');
    }
};

// 小汽车抽象类
VehicleFactory.Car = function() {
    this.type = 'car';
};
VehicleFactory.Car.prototype = {
    getPrice: function() { return new Error('抽象方法不能调用'); },
    getSpeed: function() { return new Error('抽象方法不能调用'); }
};

// 公交车抽象类
VehicleFactory.Bus = function() {
    this.type = 'bus';
};
VehicleFactory.Bus.prototype = {
    getPrice: function() { return new Error('抽象方法不能调用'); },
    getSpeed: function() { return new Error('抽象方法不能调用'); }
};

// 货车抽象类
VehicleFactory.Truck = function() {
    this.type = 'truck';
};
VehicleFactory.Truck.prototype = {
    getPrice: function() { return new Error('抽象方法不能调用'); },
    getSpeed: function() { return new Error('抽象方法不能调用'); }
};

// 创建产品子类继承相应的产品簇抽象类
// 宝马汽车子类
var BMW = function(price, speed) {
    this.price = price;
    this.speed = speed;
}
//抽象工厂实现对Car抽象类的继承
VehicleFactory(BMW, 'Car');
BMW.prototype.getPrice = function() { return this.price };
BMW.prototype.getSpeed = function() { return this.speed };

// 公交车...
// 货车...

4,命令模式:

     定义:用来对方法调用进行参数化处理和传送,经过这样处理过的方法调用可以在任何需要的时候执行。

       需求:有时候需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是什么,此时希望用一种松耦合的方式来设计软件,使得请求发送者和请求接收者能够消除彼此之间的耦合关系。

      实现:将函数的调用、请求和操作封装成一个单一的对象。

 1 var setCommand = function(button,func) {
 2     button.onclick = function(){
 3         func();
 4     }
 5  }; 
 6  var MenuBar = {
 7     refersh: function(){
 8         alert("刷新菜单界面");
 9     }
10  };
11  var SubMenu = {
12     add: function(){
13         alert("增加菜单");
14     }
15  };
16  // 刷新菜单
17  var RefreshMenuBarCommand = function(receiver) {
18     return function(){
19         receiver.refersh();    
20     };
21  };
22  // 增加菜单
23  var AddSubMenuCommand = function(receiver) {
24     return function(){
25         receiver.add();    
26     };
27  };
28  var refershMenuBarCommand = RefreshMenuBarCommand(MenuBar);
29  // 增加菜单
30  var addSubMenuCommand = AddSubMenuCommand(SubMenu);
31  setCommand(b1,refershMenuBarCommand);
32 
33  setCommand(b2,addSubMenuCommand);

5,职责链模式:

      定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。(大函数分割成一个个小函数,清晰,各司其职)

      需求:代码不清晰,可读性差,拆分函数。

      实现:

//----------------------改造前---------------
var order = function( orderType, pay, stock ){ if ( orderType === 1 ){ // 500 元定金购买模式 if ( pay === true ){ // 已支付定金 console.log( '500 元定金预购, 得到 100 优惠券' ); }else{ // 未支付定金,降级到普通购买模式 if ( stock > 0 ){ // 用于普通购买的手机还有库存 console.log( '普通购买, 无优惠券' ); }else{ console.log( '手机库存不足' ); } } } else if ( orderType === 2 ){ // 200 元定金购买模式 if ( pay === true ){ console.log( '200 元定金预购, 得到 50 优惠券' ); }else{ if ( stock > 0 ){ console.log( '普通购买, 无优惠券' ); }else{ console.log( '手机库存不足' ); } } } else if ( orderType === 3 ){ if ( stock > 0 ){ console.log( '普通购买, 无优惠券' ); }else{ console.log( '手机库存不足' ); } } }; order( 1 , true, 500); // 输出: 500 元定金预购, 得到 100 优惠券
//--------------------- 改造后----------------------------
// 500 元订单 var order500 = function( orderType, pay, stock ){ if ( orderType === 1 && pay === true ){ console.log( '500 元定金预购, 得到 100 优惠券' ); }else{ order200( orderType, pay, stock ); // 将请求传递给 200 元订单 } }; // 200 元订单 var order200 = function( orderType, pay, stock ){ if ( orderType === 2 && pay === true ){ console.log( '200 元定金预购, 得到 50 优惠券' ); }else{ orderNormal( orderType, pay, stock ); // 将请求传递给普通订单 } }; // 普通购买订单 var orderNormal = function( orderType, pay, stock ){ if ( stock > 0 ){ console.log( '普通购买, 无优惠券' ); }else{ console.log( '手机库存不足' ); } }; // 测试结果: order500( 1 , true, 500); // 输出:500 元定金预购, 得到 100 优惠券 order500( 1, false, 500 ); // 输出:普通购买, 无优惠券 order500( 2, true, 500 ); // 输出:200 元定金预购, 得到 500 优惠券 order500( 3, false, 500 ); // 输出:普通购买, 无优惠券 order500( 3, false, 0 ); // 输出:手机库存不足

 

 

 

 

             

               

             

 

转载于:https://www.cnblogs.com/smlp/p/9776789.html

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
全书pdf 210M, 共分9个分卷, 这是第2分卷 中文名: 精通CSS与HTML设计模式 英文名: Pro CSS and HTML Design Patterns 资源格式: PDF 版本: 中文版高清扫描版&英文版 发行时间: 2008年9月 地区: 大陆,美国 语言: 简体中文,英文 简介: 本书是一部非常实用的CSS 与HTML(XHTML)解决方案手册。书中包含了350 多种可以立即使用的设计模式(涉及文本、背景、边框、图片、表格、布局等多方面),并介绍了每种模式的原理和使用。每种设计模式、示例和源代码都经过了精心设计,易于实现和使用。通过阅读此书,可大大提高读者在Web 设计和开发中的效率和创造力。 本书结构清晰,示例丰富,实践性强,适用于所有Web 开发和设计人员。 编辑推荐 Amazon盛誉图书,业界专家十余年功力结晶,参透CSS与HTML,350多种可以立刻用于实战的设计模式,Web设计与开发人员的必备参考书。 “不管你是什么水平的开发人员,本书都是必备的参考书。”          ——Jonathan Snook。著名web程序员,The Art andScience of CSS一书作者  “我太喜欢这本书了。事实上我买了两本。一本放在公司,一本放在家里……本书讲解非常系统,既值得通读,也是绝佳的参考书……赶紧买一本好好研读吧。”             ——JavaRarlch.com 由于浏览器不兼容、缺乏开发环境支持等因素。Web开发至今仍然是一项难言轻松的工作。事实上,为了简化Web开发,全球广大程序员已经开发了各种技术、众多框架和库,甚至出现五花八门的旁门左道。但是。“银弹”并没有出现。 本书中。Web开发专家MlchaeI Bowers通过350多种设计模式总结了自己多年的Web开发经验,并详细讲解了每种模式的工作原理。每种设计模式、示例和源代码都经过了精心设计,可以很方便地在实际项目中使用。本书既是一部优秀的教程。可以系统而深入地学习CSS和HTML;也是不可或缺的参考书,可以大大提高你在Web设计和开发中的效率和创造力。 作者简介 Michael Bowers,资深Web开发专家,有18年专业软件开发经验。曾经作为首席软件工程师和架构师开发过各种项目,包括许多网站、应用程序框架、编译器、自定义语言,自动化工厂和销售管理系统。他拥有音乐理论硕士学位,是一名优秀的钢琴家。 图书信息: 书名:精通CSS与HTML设计模式 (Pro CSS and HTML Design Patterns) 作者:[美]Michael Bowers 著,刘申 朱瑜敏 鲁奇 译 出版社:人民邮电出版社 出版日期:2008年9月 ISBN:978-7-115-18553-2 页数:479页 定价:¥69.00 扫描:400DPI,黑白 这本书因为是奇偶页左右对照看的,所以直接扫描双页,没有拆分。 目录: 第1章 设计模式:轻松搞定CSS! 第2章 HTML设计模式 第3章 CSS选择符与继承 第4章 盒模型 第5章 盒模型的尺寸 第6章 盒模型的属性 第7章 定位模型 第8章 定位:缩进、偏移与对齐 第9章 定位:进阶 第10章 为文本赋予样式 第11章 分割内容 第12章 对齐内容 第13章 块状元素 第14章 图片 第15章 表格 第16章 列布局 第17章 布局 第18章 字母下沉 第19章 强调框和引用 第20章 提示框 索引....
前端框架中也可以应用设计模式来帮助开发人员更好地组织和管理代码。有一些常见的设计模式前端开发中被广泛使用,例如: 1. MVC模式(Model-View-Controller):MVC模式是一种常见的架构模式,用于将应用程序的逻辑、数据和用户界面分离。在前端开发中,可以使用MVC模式来将数据、视图和控制器分离,以便更好地组织和管理代码。 2. 观察者模式(Observer Pattern):观察者模式用于实现对象之间的一对多依赖关系。在前端开发中,观察者模式可以用于实现事件监听和响应,例如当用户点击按钮时,触发相应的事件处理函数。 3. 单例模式(Singleton Pattern):单例模式用于确保一个类只有一个实例,并提供一个全局访问点。在前端开发中,单例模式可以用于管理全局状态、共享资源或提供统一的配置管理。 4. 工厂模式(Factory Pattern):工厂模式用于创建对象的过程中,将创建逻辑和具体对象的实现分离。在前端开发中,工厂模式可以用于创建不同类型的对象,例如根据用户的角色类型创建不同的导航菜单。 以上只是几个常见的设计模式前端开发中的应用,实际上还有更多的设计模式可以用于解决特定的问题。对于前端开发人员来说,了解不同的设计模式,并根据具体的需求进行选择和应用,可以帮助提高代码的可维护性和扩展性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [前端开发中常用的几种设计模式](https://blog.csdn.net/shadowfall/article/details/112001884)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值