大话装饰器模式

543 阅读2分钟

这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战

介绍

本期我们来聊聊装饰器模式,它可以动态地给一个对象添加一些额外的职责,又不会影响到原来的功能,这可比生成子类更为灵活,是一种常见的设计模式,它也是继承的一种替代方案。

举个栗子吧,魂斗罗相信我们小时候都玩过,主角移动过程中会吃到各式各样的BUFF,吃完后武器就会发生变化,有的是霰弹枪,有的是喷火,有的是激光等等各式各样的效果,但是射击动作执行并没有改变,改变的只是武器的射击效果,这时就可以用装饰器模式来去追加/更改这些武器效果。

微信截图_20220212164104.png

概念

装饰器模式属于一种结构型模式,它是作为现有的类的一个包装。主要是允许向一个现有的对象添加新的功能,同时又不改变其结构。

案例

接下来,就是要实现一下魂斗罗的武器切换。

var player = {
	fire:function(){
		console.log("—执行射击—")
	}
}

var weaponS = function(){
	console.log("*霰弹武器*")
}
var weaponF = function(){
	console.log("*喷火武器*")
}
var weaponL = function(){
	console.log("*激光武器*")
}

var _player_fire = player.fire;
player.fire = function(){
	_player_fire();
	weaponS();
}
player.fire()

console.log("~~~~~~切换武器~~~~~~~")

player.fire = function(){
	_player_fire();
	weaponF();
}
player.fire()

console.log("~~~~~~切换武器~~~~~~~")

player.fire = function(){
	_player_fire();
	weaponL();
}
player.fire()

微信截图_20220212180400.png

这里我们就看到了,我们并没有更改player原本的动作没有修改,而是仅仅的将武器的功能进行了扩展,而且切换也不会产生对原有的射击动作产生影响。

ES装饰器

因为涉及到装饰器模式的业务确实非常多,在 ES7 中提出了一个装饰器的新语法。

装饰器是一种函数,写成@ + 函数名

它可以放在类和类方法的定义前面,可以十分方便的用来装饰整个类。

@decorator
class className {}

// 等同于
class className {}
className = decorator(className) || className;

使用详见阮一峰的ECMAScript 6 入门

但目前依然是一个提案状态,以后是否有更改依然未知。

使用场景

  1. 扩展一个类的功能。
  2. 动态增加功能,动态撤销。

结语

通过刚才的讲述不难发现,装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能,十分的灵活。

我们在开发中,比如日志统计,头像框装饰替换等等,都可以考虑使用它来完成。