装饰者模式(Decorator)
在
不改变原对象
的基础上,通过对其进行包装拓展(添加属性或者方法)
使原有对象可以满足用户的更复杂需求。
- 需求:
- 当输入框获取到焦点时,定义并显示提示文案;
- 追加需求:当输入框获取焦点时,把输入框边框变成红色;
<input id="input-val" type="text">
<span id="warn-text" style="color: red;"></span>
需求一:当输入框获取到焦点时,定义并显示提示文案;
/**
* 需求1:当输入框获取到焦点时,显示提示文案
*/
const input = document.getElementById('input-val');
// 获取焦点
input.onfocus = function (e) {
console.log('旧', e);
showWarn('warn-text', '请输入不大于10个字符的名字!')
};
/**
* 显示警告提示
* @param {string} id DOM id
* @param {string} text 提示内容
*/
const showWarn = function (id, text) {
const el = document.getElementById(id);
el.innerText = text;
el.style.display = 'inline';
};
需求二:追加需求:当输入框获取焦点时,把输入框边框变成红色;
方式一:
直接进行历史代码修改
const input = document.getElementById('input-val'); // 获取焦点 input.onfocus = function (e) { e.target.style.border = '1px solid red'; showWarn('warn-text', '请输入不大于10个字符的名字!') }; /** * 显示警告提示 * @param {string} id DOM id * @param {string} text 提示内容 */ const showWarn = function (id, text) { const el = document.getElementById(id); el.innerText = text; el.style.display = 'inline'; };
方式二:
装饰者模式进行需求追加修改
/** * 定义装饰者 * @param {string} id DOM id * @param {function} fn 追加方法 */ const decorator = function (id, fn) { // 获取事件源 const el = document.getElementById(id); // 判断事件源是否已经绑定了事件(未定义事件时el.onfocus为null) if (typeof el.onfocus === 'function') { // 缓存事件源事件(保留历史事件) const oldEventFn = el.onfocus; // 追加新的事件 el.onfocus = function (e) { // 执行历史事件 oldEventFn(e); // 执行追加的事件 fn(e); }; } else { // 事件源未绑定事件,直接为事件源添加新增回调函数 el.onfocus = fn; } }; decorator('input-val', (e) => { console.log('新', e); e.target.style.border = '1px solid red'; });
适配器模式和装饰者模式区别
适配器模式
- 对原有对象适配,添加的方法与原有方法功能上大致相似
- 使用适配器时我们新增的方法是要调用原来的方法
装饰者模式
- 装饰者提供的方法与原来的方法功能项是有一定区别的
- 在装饰者模式中,不需要了解对象原有的功能,并且对象原有的方法照样可以原封不动地使用