装饰者模式是为已有的功能动态地添加更多功能的一种方式。当系统需要新功能的时候,是向旧的类中添加新的代码。这些新加的代码通常装饰了原有类的核心职责或主要行为,在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度,而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。装饰者提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。
装饰者模式类图:
在装饰者模式中各个角色有:
- 抽象构件(Phone)角色:给出一个抽象接口,以规范准备接受附加责任的对象。
- 具体构件(AppPhone)角色:定义一个将要接收附加责任的类。
- 装饰(Dicorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
- 具体装饰(Sticker和Accessories)角色:负责给构件对象 ”贴上“附加的责任。
C#的装饰模式:
class Person { public Person() { } private string name; public Person(string name) { this.name = name; } public virtual void Show() { Console.WriteLine("装扮的{0}", name); } } class Finery : Person { protected Person component; //打扮 public void Decorate(Person component) { this.component = component; } public override void Show() { if (component != null) { component.Show(); } } } class TShirts : Finery { public override void Show() { Console.Write("大T恤 "); base.Show(); } } class BigTrouser : Finery { public override void Show() { Console.Write("垮裤 "); base.Show(); } } class Sneakers : Finery { public override void Show() { Console.Write("破球鞋 "); base.Show(); } } class Suit : Finery { public override void Show() { Console.Write("西装 "); base.Show(); } } class Tie : Finery { public override void Show() { Console.Write("领带 "); base.Show(); } } class LeatherShoes : Finery { public override void Show() { Console.Write("皮鞋 "); base.Show(); } }class Program { static void Main(string[] args) { Person xc = new Person("小菜"); Console.WriteLine("\n第一种装扮:"); Sneakers pqx = new Sneakers(); BigTrouser kk = new BigTrouser(); TShirts dtx = new TShirts(); pqx.Decorate(xc); kk.Decorate(pqx); dtx.Decorate(kk); dtx.Show(); Console.WriteLine("\n第二种装扮:"); LeatherShoes px = new LeatherShoes(); Tie ld = new Tie(); Suit xz = new Suit(); px.Decorate(xc); ld.Decorate(px); xz.Decorate(ld); xz.Show(); Console.WriteLine("\n第三种装扮:"); Sneakers pqx2 = new Sneakers(); LeatherShoes px2 = new LeatherShoes(); BigTrouser kk2 = new BigTrouser(); Tie ld2 = new Tie(); pqx2.Decorate(xc); px2.Decorate(pqx); kk2.Decorate(px2); ld2.Decorate(kk2); ld2.Show(); Console.Read(); } }
js模拟高级语言的装饰模式:
var Finery = function(){}; Finery.prototype.decorate = function(component){ this.component = component; }; Finery.prototype.shown = function(){ this.component && this.component.show(); }; var Person = function(name){ this.name = name; }; Person.prototype.show = function(){ alert('装扮的' + this.name); }; var TShirts = function(){}; TShirts.prototype = new Finery(); TShirts.prototype.show = function(){ alert('大T恤'); this.shown(); }; var BigTrouser = function(){}; BigTrouser.prototype = new Finery(); BigTrouser.prototype.show = function(){ alert('垮裤'); this.shown(); }; var Sneakers = function(){}; Sneakers.prototype = new Finery(); Sneakers.prototype.show = function(){ alert('破球鞋'); this.shown(); }; var Suit = function(){}; Suit.prototype = new Finery(); Suit.prototype.show = function(){ alert('西装'); this.shown(); }; var Tie = function(){}; Tie.prototype = new Finery(); Tie.prototype.show = function(){ alert('领带'); this.shown(); }; var LeatherShoes = function(){}; LeatherShoes.prototype = new Finery(); LeatherShoes.prototype.show = function(){ alert('皮鞋'); this.shown(); }; //调用: var xc = new Person("小菜"); alert('第一种装扮:'); var pqx = new Sneakers(xc); var kk = new BigTrouser(pqx); var dtx = new TShirts(kk); pqx.decorate(xc); kk.decorate(pqx); dtx.decorate(kk); dtx.show();
js语言特性的装饰模式:
var person = { show:function(name){ alert('装扮的' + name); } }; var tShirts = function(){ alert('大T恤'); }; var bigTrouser = function(){ alert('垮裤'); }; var sneakers = function(){ alert('破球鞋'); }; var suit = function(){ alert('西装'); }; var tie = function(){ alert('领带'); }; var leatherShoes = function(){ alert('皮鞋'); }; //装饰者: var person1 = person.show; person.show = function(name){ person1(name); sneakers(); }; var person2 = person.show; person.show = function(name){ person2(name); bigTrouser(); }; var person3 = person.show; person.show = function(name){ person3(name); tShirts(); }; //调用: person.show('小菜');
js通用装饰者:
Function.prototype.before = function(beforefn){ var _self = this; //保存原函数的引用 return function(){ //返回包含了原函数和新函数的“代理”函数 beforefn.apply(this,arguments); //执行新函数,且保证this不被劫持,新函数接受的参数 //也会被原封不动地传入原函数,新函数在原函数之前执行 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; } };
值得提到的是,上面的AOP实现是在Function.prototype上添加before和after方法,但许多人不喜欢这种污染原型的方式,那么我们可以做一些变通,把原函数和新函数都作为参数传入before或者after方法:
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 = before(a, function(){ alert(1); }); a();