JavaScript设计模式(装饰者模式)
一、模拟传统面向对象语言的装饰者模式:
// 首先是原始的飞机类
var Plane = function(){
}
Plane.prototype.fire = function(){
console.log( '发射普通子弹' );
} // 接下来增加两个装饰类,分别是导弹和原子弹:
var MissileDecorator = function( plane ){
this.plane = plane;
}
MissileDecorator.prototype.fire = function(){
this.plane.fire();
console.log( '发射导弹' );
} var AtomDecorator = function( plane ){
this.plane = plane;
}
AtomDecorator.prototype.fire = function(){
this.plane.fire();
console.log( '发射原子弹' );
} // 最后看看测试结果
var plane = new Plane();
plane = new MissileDecorator( plane );
plane = new AtomDecorator( plane );
plane.fire();
// 分别输出: 发射普通子弹、发射导弹、发射原子弹
二、装饰者也是包装器
三、回到JavaScript的装饰者
var plane = {
fire: function(){
console.log( '发射普通子弹' );
}
}
var missileDecorator = function(){
console.log( '发射导弹' );
}
var atomDecorator = function(){
console.log( '发射原子弹' );
}
var fire1 = plane.fire;
plane.fire = function(){
fire1();
missileDecorator();
}
var fire2 = plane.fire;
plane.fire = function(){
fire2();
atomDecorator();
}
plane.fire();
// 分别输出: 发射普通子弹、发射导弹、发射原子弹
四、用AOP装饰函数
Function.prototype.before = function( beforefn ){
// 保存原函数的引用
var __self = this;
// 返回包含了原函数和新函数的"代理"函数
return function(){
// 执行新函数,且保证this不被劫持,新函数接受的参数
// 也会被原封不动地传入原函数,新函数在原函数之前执行
beforefn.apply( this, arguments );
return __self.apply( this, arguments ); // 执行原函数并返回原函数的执行结果, // 并且保证this不被劫持
}
}
Function.prototype.after = function( afterfn ){
var __self = this;
return function(){
var ret = __self.apply( this, arguments );
afterfn.apply( this, arguments );
return ret;
}
};
// 实例1:
document.getElementById = document.getElementById.before(function() {
alert (1);
});
var button = document.getElementById('button');
console.log(button) // 实例2(改造window.onload):
window.onload = function(){
alert (11);
}
window.onload = ( window.onload || function(){} ).before(function(){
alert (22);
}).after(function(){
alert (33);
}).after(function(){
alert (44);
});
var before = function( fn, beforefn ){
return function(){
beforefn.apply( this, arguments );
return fn.apply( this, arguments );
}
}
var a = before( function(){
alert (3)
}, function(){
alert (2)
}
);
a = a();
五、AOP的应用实例
5.1:假设现在我们需要点击一个按钮后既要负责打开登录浮层,和负责数据上报,我们看到在showLogin函数里,这是两个层面的功能,在此处却被耦合在一个函数里。
{/* <button tag="login" id="button">点击打开登录浮层</button> */}
var showLogin = function(){
console.log( '打开登录浮层' );
log( this.getAttribute( 'tag' ) );
}
var log = function( tag ){
console.log( '上报标签为: ' + tag );
// (new Image).src = 'http:// xxx.com/report?tag=' + tag; // 真正的上报代码略
}
document.getElementById( 'button' ).onclick = showLogin;
// 使用 AOP分离之后,代码如下:
var showLogin = function(){
console.log( '打开登录浮层' );
}
var log = function(){
console.log( '上报标签为: ' + this.getAttribute( 'tag' ) );
}
showLogin = showLogin.after(log); // 打开登录浮层之后上报数据
document.getElementById('button').onclick = showLogin;
5.2:插件式的表单验证
<body>
用户名:<input id="username" type="text"/>
密码: <input id="password" type="password"/>
<input id="submitBtn" type="button" value="提交">
</body>
var username = document.getElementById( 'username' ),
password = document.getElementById( 'password' ),
submitBtn = document.getElementById( 'submitBtn' );
var formSubmit = function(){
if ( username.value === '' ){
return alert ( '用户名不能为空' );
}
if ( password.value === '' ){
return alert ( '密码不能为空' );
}
var param = {
username: username.value,
password: password.value
}
ajax( 'http:// xxx.com/login', param );
}
submitBtn.onclick = function(){
formSubmit();
}
Function.prototype.before = function( beforefn ){
var __self = this;
return function(){
if ( beforefn.apply( this, arguments ) === false ){
// beforefn 返回 false 的情况直接 return,不再执行后面的原函数 return;
}
return __self.apply( this, arguments );
}
}
var validata = function(){
if ( username.value === '' ){
alert ( '用户名不能为空' );
return false;
}
if ( password.value === '' ){
alert ( '密码不能为空' );
return false;
}
}
var formSubmit = function(){
var param = {
username: username.value,
password: password.value
}
ajax( 'http:// xxx.com/login', param );
}
formSubmit = formSubmit.before( validata );
submitBtn.onclick = function(){
formSubmit();
}
六:装饰者模式和代理模式
JavaScript设计模式(装饰者模式)的更多相关文章
- javascript设计模式——装饰者模式
前面的话 在程序开发中,许多时候都并不希望某个类天生就非常庞大,一次性包含许多职责.那么可以使用装饰者模式.装饰者模式可以动态地给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象.本文将 ...
- 从ES6重新认识JavaScript设计模式: 装饰器模式
1 什么是装饰器模式 向一个现有的对象添加新的功能,同时又不改变其结构的设计模式被称为装饰器模式(Decorator Pattern),它是作为现有的类的一个包装(Wrapper). 可以将装饰器理解 ...
- JavaScript设计模式----装饰者模式
装饰者模式的定义: 装饰者(decorator)模式能够在不改变对象自身的基础上,在程序运行期间给对像动态的添加职责.与继承相比,装饰者是一种更轻便灵活的做法. 装饰者模式的特点: 可以动态的给某个对 ...
- 读书笔记之 - javascript 设计模式 - 装饰者模式
本章讨论的是一种为对象增添特性的技术,它并不使用创建新子类这种手段. 装饰者模式可以透明地把对象包装在具有同样接口的另一对象之中,这样一来,你可以给一些方法添加一些行为,然后将方法调用传递给原始对象. ...
- JavaScript设计模式—装饰器模式
装饰器模式介绍 为对象添加新的功能,不改变其原有的结构和功能,原有的功能还是可以使用,跟适配器模式不一样,适配器模式原有的已经不能使用了,装饰器示例比如手机壳 UML类图和代码示例 Circle示原来 ...
- JavaScript设计模式之----组合模式
javascript设计模式之组合模式 介绍 组合模式是一种专门为创建Web上的动态用户界面而量身制定的模式.使用这种模式可以用一条命令在多个对象上激发复杂的或递归的行为.这可以简化粘合性代码,使其更 ...
- Java设计模式——装饰者模式
JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...
- JAVA设计模式--装饰器模式
装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...
- javascript的装饰者模式Decorator
刚开始看这段代码有点绕,现在回过头来看,so easy! Function.prototype.before = function(beforefn){ var _self = this; retur ...
- 从源码角度理解Java设计模式——装饰者模式
一.饰器者模式介绍 装饰者模式定义:在不改变原有对象的基础上附加功能,相比生成子类更灵活. 适用场景:动态的给一个对象添加或者撤销功能. 优点:可以不改变原有对象的情况下动态扩展功能,可以使扩展的多个 ...
随机推荐
- 安装wget 、 wget命令
今天给服务器安装新LNMP环境时,wget 时提示 -bash:wget command not found,很明显没有安装wget软件包.一般linux最小化安装时,wget不会默认被安装. 可以通 ...
- OUC_Summer Training_ DIV2_#16 725
今天做了这两道题真的好高兴啊!!我一直知道自己很渣,又贪玩不像别人那样用功,又没有别人有天赋.所以感觉在ACM也没有学到什么东西,没有多少进步.但是今天的B题告诉我,进步虽然不明显,但是只要坚持努力的 ...
- LeetCode 44. 通配符匹配(Wildcard Matching)
题目描述 给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配. '?' 可以匹配任何单个字符. '*' 可以匹配任意字符串(包括空字符串). 两个字符串完 ...
- 从char到QChar
char类型是c/c++中内置的类型,描述了1个字节的内存信息的解析.比如: char gemfield=’g’; 那么在由gemfield标记的这块内存的大小就是1个字节,信息就是01100111, ...
- QAbstractTableModel中的data()到底执行几遍???
发现问题的过程 1.一个普通的继承 QAbstractTableModel 的类 class CurrencyModel : public QAbstractTableModel { public: ...
- MySql、PostgreSql、SqlServer三种数据库的造数存储过程实例
主要实例:把临时表tmp_table数据插入到目标表target_table 一.MySql造数存储过程实例 mysql造数 -- 第一步,创建临时表 CREATE TEMPORARY TABLE I ...
- 解决Android Studio 升级时提示 Connection failed. Please check your network connection and try again问题
一,问题: 无论mac还是windows可能都会出现这个问题,解决方案大同小异,就是修改VMOptions而已. 解决方案: Windows: 在\Android Studio\bin目录下找到 st ...
- Java日志体系(六)log4j2
1.1 简介 log4j2,一个日志的实现框架,是log4j的升级版本,于2014年7月正式亮相.与第一代log4j不同,log4j2完全重写了log4j的日志实现,并不是在原有基础上进行的升级,解决 ...
- lumen怎么得到当前Uri的控制器、Action、路由规则
<?php namespace App\Http\Controllers; class HelloController extends Controller { public function ...
- centos7安装kvm及kvm管理
一.安装kvm 查看CPU是否支持虚拟化 grep -E 'svm|vmx' /proc/cpuinfo - vmx is for Intel processors - svm is for AMD ...