javaScript设计模式之装饰者模式

1.介绍

       装饰者模式能够在不改变对象自身的基础上,在程序运行期间对对象动态的添加职责。与继承相比,装饰者是一种更加轻便灵活的做法,这是一种“即用即付”的方式。

2.实例引入

<span style="font-size:14px;">	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();</span>
这种给对象以一条链的方式进行引用,形成了一个聚合对象,这些对象都拥有相同的接口(fire)方法,当请求达到链中的某个对象时,这个对象会执行自身的操作,随后把请求转发给链中的下一个对象。

改写对象或者对象的某个方法,并不需要使用“类”来装饰实现装饰者模式:

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装饰函数,其中把职责分为更细的函数,随后通过装饰者把他们合并到一起。

 <html>
<body>
	用户名:<input id="username" type="text"/>

	密码: <input id="password" type="password"/>
	<input id="submitBtn" type="button" value="提交"></button>
</body>
<script>
	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 ); // ajax 具体实现略
	}

	submitBtn.onclick = function(){
		formSubmit();
	}


	var validata = function(){
		if ( username.value === '' ){
			alert ( '用户名不能为空' );
			return false;
		}
		if ( password.value === '' ){
			alert ( '密码不能为空' );
			return false;
		}
	}

	var formSubmit = function(){
		if ( validata() === false ){ // 校验未通过
			return;
		}
		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();
	}
	
</script>
</html>
       这段代码验证和输入完全分离开来,他们不再有任何偶和关系。其中formSubmit 函数除了提交ajax请求以外,还要验证用户输入的合法性;分离校验输入和提交ajax请求的代码,把输入的逻辑放到validata函数中,并且约定validate函数返回false的时候表示验证未通过。

总结

       装饰者模式和代理模式的结构看起来非常像,这两种模式都描述了怎样为对象提供一定程度上的间接引用,他们实际上都保留了对另外一个对象的引用,并且对那个对象发送请求。代理模式强调Proxy与它的实体之间的关系,这种关系一开始就被确定,可以静态的表达。而装饰者模式用于一开始不能确定对象的全部功能时,代理模式通常只有一层代理-本体的引用,而装饰者模式通常会形成一条长长的装饰链。比如在代理图片预加载的例子中,本体负责设置img节点的src,代理则提供预加载的功能,这看起来也是“加入行动”的一种方式;而装饰者模式是实实在在的为对象增加新的职责和行为,而代理做的事情还是和本体一样,最终都是设置src。


猜你喜欢

转载自blog.csdn.net/shoushou71/article/details/51766456
今日推荐