代理模式

代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。

生活中有很多的代理模式的场景。例如,明星有经纪人作为代理,老板有秘书作为代理等等,当有事情的时候,会找到经纪人或秘书,再由他们转达给明星或者老板。

首先通过一个例子来简单的了解了解,故事是这样的...

以下故事纯属虚构,不要当真

大家都知道三顾茅庐(不知道的百度一下)吧,诸葛亮何许人也,厉害的不要不要的,名声在外啊。好巧不巧刘备知道了,刘备心想:“这么厉害的人跟着我,岂不美哉,统一三国起步指日可待”,于是,刘备带着礼物就去请人家了。正常流程应该这样:

// 刘备
let bei = {
// 邀请
invite(){
liang.reception('草鞋')
}
}
// 亮
let liang = {
// 收到礼物
reception(gift){
console.log('亮收到礼物:' + gift)
}
}
// 调用方法
bei.invite()

但是呢,事实不是这样的,诸葛亮心想:“刘备一卖草鞋的就想见我?”,于是呢,刘备只见到了门童:

// 刘备
let bei = {
// 邀请
invite(){
mentong.reception('草鞋')
}
}
// 门童
let mentong = {
// 接收礼物
reception(gift){
console.log('门童收到礼物:' + gift)
// 给诸葛亮
liang.reception('草鞋')
}
}
// 亮
let liang = {
// 接收礼物
reception(gift){
console.log('亮收到礼物:' + gift)
}
}
// 调用方法
bei.invite()

所以,刘备就只能把礼物给了门童,门童在交给了诸葛亮,然后诸葛亮一看,好家伙,草鞋。。。

到此可以看成一个简单的代理了

保护代理和虚拟代理

保护代理

诸葛亮收到草鞋后也是无语,然后叫来门童告诉他:“以后呢,送草鞋的,你就不用给我了,自己看着处理就好了”,门童心领神会,表示ok

// 门童
let mentong = {
// 接收礼物
reception(gift){
console.log('门童收到礼物:' + gift)
if(gift !== '草鞋'){
// 给诸葛亮
liang.reception(gift)
}
}
}

通过代理(门童)来处理一些不必要的东西,过滤掉无用信息,这可以理解为 保护代理

但在 JavaScript 并不容易实现保护代理,因为我们无法判断谁访问了某个对象。

虚拟代理

话题又回到刘备这,刘备这连着送礼都两天了,也见不到人。有人就给他出了个方法。于是啊就去找到门童说:“小兄弟这钱你拿着,你帮我买点礼物给诸葛先生”,门童也是诧异什么时候变聪明了

// 门童
let mentong = {
// 接收礼物
reception(){
// 拿钱去买礼物
let book = new Book()
// 给诸葛亮
liang.reception(book)
}
}

诸葛亮这回挺开心,于是就答应见刘备了(~ ̄▽ ̄)~

这可以理解为 虚拟代理

虚拟代理实现图片预加载

注:I know 这个例子大家可能都看过了,因为没有想到更好的例子(想到了更改补上),但是这个例子我会一行一行讲解清楚的o( ̄▽ ̄)ブ

平时由于网络的不佳,导致图片出来前会有一片空白。所以我们限用一张 loading 图片占位,在异步方式加载图片

没用代理

// 创建一个本体对象
var myImage = (function(){
// 创建标签
var imgNode = document.createElement( 'img' );
// 添加到页面
document.body.appendChild( imgNode );
return {
// 设置图片的src
setSrc: function( src ){
// 更改src
imgNode.src = src;
}
}
})(); myImage.setSrc( 'http:// image.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );

引入代理对象

// 创建一个本体对象
var myImage = (function(){
// 创建标签
var imgNode = document.createElement( 'img' );
// 添加到页面
document.body.appendChild( imgNode );
return {
// 设置图片的src
setSrc: function( src ){
// 更改src
imgNode.src = src;
}
}
})(); // 创建代理对象
var proxyImage = (function(){
// 创建一个新的img标签
var img = new Image;
// img 加载完成事件
img.onload = function(){
// 调用 myImage 替换src方法
myImage.setSrc( this.src );
}
return {
// 代理设置地址
setSrc: function( src ){
// 预加载 loading
myImage.setSrc( 'file:// /C:/Users/svenzeng/Desktop/loading.gif' );
// 赋值正常图片地址
img.src = src;
}
}
})(); proxyImage.setSrc( 'http:// image.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );

现在我们可以通过 proxyImage 间接地访问 MyImageproxyImage 控制了客户对 MyImage 的访问,并

且在此过程中提前把 img 节点的 src 设置为了一张本地的 loading 图片


现在再来看看不用代理来实现预加载

// 创建一个本体对象
var MyImage = (function(){
// 创建标签
var imgNode = document.createElement( 'img' );
// 添加到页面
document.body.appendChild( imgNode );
// 创建一个新的img标签
var img = new Image;
// img 加载完成
img.onload = function(){
// 替换地址
imgNode.src = img.src;
};
return {
// 设置地址
setSrc: function( src ){
// 本地 loading 图片地址
imgNode.src = 'file:// /C:/Users/svenzeng/Desktop/loading.gif';
// 赋值正常图片地址
img.src = src;
}
}
})(); MyImage.setSrc( 'http:// image.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );

现在来看看没有用代理的代码

  • 违反了单一原则。MyImage除了要负责img节点的设置,还要负责预加载图片。这导致在处理其中一个职责时会因其强耦合性影响另一个职责。
  • 违反了开闭原则。倘若以后要去掉预加载,只能去更改MyImage对象,这不符合开闭原则。

代理和本体接口的一致性

如果有一天我们不再需要预加载,那么就不再需要代理对象,可以选择直接请求本体。其中关键是代理对象和本体都对外提供了 setSrc 方法,在客户看来,代理对象和本体是一致的, 代理接手请求的过程对于用户来说是透明的,用户并不清楚代理和本体的区别这样做有两个好处:

  • 用户可以放心地请求代理,他只关心是否能得到想要的结果。
  • 在任何使用本体的地方都可以替换成使用代理。(是不是有点里氏替换的味道)
// 预加载
proxyImage.setSrc( 'http:// image.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' ); // 不用预加载
myImage.setSrc( 'http:// image.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );

缓存代理

再举一个经典的例子啊(没想到别的,以后想到了再换(~ ̄▽ ̄)~)

乘积函数

var mult = function(){
console.log( '开始计算乘积' );
var a = 1;
for ( var i = 0, l = arguments.length; i < l; i++ ){
a = a * arguments[i];
}
return a;
};

缓存代理函数

var proxyMult = (function(){
// 缓存结果
var cache = {};
return function(){
// 将参数转化为字符串
var args = Array.prototype.join.call( arguments, ',' );
// 遍历缓存结果如果存在直接返回结果
if ( args in cache ){
return cache[ args ];
}
// 不存在进行计算并保存结果
return cache[ args ] = mult.apply( this, arguments );
}
})(); proxyMult( 1, 2, 3, 4 ); // 输出:24
proxyMult( 1, 2, 3, 4 ); // 输出:24

我们也可以动态创建代理

/**************** 计算乘积 *****************/
var mult = function(){
var a = 1;
for ( var i = 0, l = arguments.length; i < l; i++ ){
a = a * arguments[i];
}
return a;
}
/**************** 计算加和 *****************/
var plus = function(){
var a = 0;
for ( var i = 0, l = arguments.length; i < l; i++ ){
a = a + arguments[i];
}
return a;
}
/**************** 创建缓存代理的工厂 *****************/
var createProxyFactory = function( fn ){
// 缓存结果
var cache = {};
return function(){
// 将参数转换成字符串
var args = Array.prototype.join.call( arguments, ',' );
// 遍历缓存结果如果存在直接返回结果
if ( args in cache ){
return cache[ args ];
}
// 不存在进行相应的计算并保存结果
return cache[ args ] = fn.apply( this, arguments );
}
}; // 创建乘法和加法
var proxyMult = createProxyFactory( mult ),proxyPlus = createProxyFactory( plus ) alert ( proxyMult( 1, 2, 3, 4 ) ); // 输出:24
alert ( proxyMult( 1, 2, 3, 4 ) ); // 输出:24
alert ( proxyPlus( 1, 2, 3, 4 ) ); // 输出:10
alert ( proxyPlus( 1, 2, 3, 4 ) ); // 输出:10

代理模式包括许多小分类,在JavaScript开发中最常用的是虚拟代理和缓存代理。虽然代理模式非常有用,但我们在编写业务代码的时候,往往不需要去预先猜测是否需要使用代理模。当真正发现不方便直接访问某个对象的时候,再编写代理也不迟。

目前对于代理模式的理解就这么多,以后有了新的理解会继续更新的,溜了溜了(~ ̄▽ ̄)~

js 设计模式——代理模式的更多相关文章

  1. js设计模式-代理模式

    1.什么是设计模式? 设计模式:在软件设计过程中常用的代码规范,针对特定的场景 2.应用场景: 麦当劳点餐  观察者模式   规定的代码格式 花店送花  :代理模式 真实对象(男同学)-----代理对 ...

  2. 9. 星际争霸之php设计模式--代理模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  3. C++设计模式——代理模式

    前言 青春总是那样,逝去了才开始回味:大学生活也是在不经意间就溜走了,现在上班的时候,偶尔还会怀念大学时,大家在一起玩游戏的时光.大学喜欢玩游戏,但是可悲的校园网,速度能把人逼疯了:还好,后来搞了一个 ...

  4. PHP设计模式-代理模式

    概念理解: 代理模式,是对简单处理程序(或指针)的增强,用于引用一个对象:这个指针被代理对象取代,代理对象位于客户端和真实程序之间,指针有一个可被多个目标利用的钩子. 参与者: client(参与者) ...

  5. Java设计模式-代理模式之动态代理(附源代码分析)

    Java设计模式-代理模式之动态代理(附源代码分析) 动态代理概念及类图 上一篇中介绍了静态代理,动态代理跟静态代理一个最大的差别就是:动态代理是在执行时刻动态的创建出代理类及其对象. 上篇中的静态代 ...

  6. 浅谈Python设计模式 - 代理模式

    声明:本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 一.在某些应用中,我们想要在访问某个对象之前执行一个或者多个重要的操作,例如,访 ...

  7. Java 之 设计模式——代理模式

    设计模式——代理模式 一.概述 1.代理模式 (1)真实对象:被代理的对象 (2)代理对象:代理真实对象的 (3)代理模式:代理对象代理真实对象,达到增强真实对象功能的目的 二.实现方式 1.静态代理 ...

  8. [Head First设计模式]抢票中的设计模式——代理模式

    系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...

  9. JAVA 设计模式 代理模式

    用途 代理模式 (Proxy) 为其他对象提供一种代理以控制对这个对象的访问. 代理模式是一种结构型模式. 结构

随机推荐

  1. react-native 标题随页面滚动显示和隐藏

    效果图如下: 代码实现: import React, {Component} from 'react'; import { ScrollView, Text, View, FlatList, } fr ...

  2. MySQL 部署分布式架构 MyCAT (五)

    分片(水平拆分) 4.全局表 业务使用场景: 如果你的业务中有些数据类似于数据字典,比如配置文件的配置, 常用业务的配置或者数据量不大很少变动的表,这些表往往不是特别大, 而且大部分的业务场景都会用到 ...

  3. liteos动态加载(十三)

    1. 概述 1.1 基本概念 动态加载是一种程序加载技术. 静态链接是在链接阶段将程序各模块文件链接成一个完整的可执行文件,运行时作为整体一次性加载进内存.动态加载允许用户将程序各模块编译成独立的文件 ...

  4. [PHP] 现代化PHP之路:composer的安装和升级

    1.下载一个脚本文件 wget https://getcomposer.org/installer 2.php执行下这个php脚本 php installer 3.把下载的文件转移到一个PATH环境变 ...

  5. 01-路由跳转 安装less this.$router.replace(path) 解决vue/cli3.0语法报错问题

    2==解决vue2.0里面控制台包的一些语法错误. https://www.jianshu.com/p/5e0a1541418b 在build==>webpack.base.conf.j下注释掉 ...

  6. bootstrap如何去除自带的样式----导航栏中的菜单实现平滑的过渡到对应的菜单区域-------动态跟换模态框中的内容

    问题1:如何去除bootstap中css中自带的overflow:hidden这个样式 今天遇见在bootstap中轮播图上的  附带图  片不能够显示出来,图片始终有一部分的高度  被隐藏了 后来通 ...

  7. 2.Java基础_Java常量

    /* 常量: 在程序执行过程中,其值不可以发生改变的量 常量分类: 字符串常量: 用双引号括起来的内容. "Hello,World!" 整数常量: 不带小数的数字. 666,-88 ...

  8. 第36课 经典问题(下)----关于string的疑问

    实例1: 下面的代码输出什么,为什么? #include <iostream> #include <string> using namespace std; int main( ...

  9. Jenkins之插件Publish HTML reports的使用

    前提: 下载插件HTML Publisher plugin 一.安装 安装好HTML Publisher plugin之后,会在新建或者编辑项目时,在[增加构建后操作步骤]出现[Publish HTM ...

  10. scrapy 爬取视频

    利用FilesPipeline 下载视频 1.setting.py # 保存log信息的文件名 LOG_LEVEL = "INFO" # LOG_STDOUT = True # L ...