装饰器模式
在不改变原对象的基础上,通过对其进行包装拓展,使原有的对象可以满足用户的更复杂需求。
装饰器的应用场景
按钮的封装,未登录点击时弹出未登录的提示
javascript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>装饰器</title>
</head>
<body>
<button id="open">打开</button>
<button id="close">关闭</button>
<script>
const Modal = (function () {
let instance = null;
return function () {
if (!instance) {
instance = document.createElement('div');
instance.innerHTML = '你还未登录!';
instance.style.display = 'none';
instance.id = 'modal';
document.body.appendChild(instance);
}
return instance;
}
})()
document.getElementById('open').onclick = function () {
const modal = new Modal()
modal.style.display = 'block'
}
document.getElementById('close').onclick = function () {
const modal = document.getElementById('modal')
if (modal) {
modal.style.display = 'none'
}
}
</script>
</body>
</html>
现在要添加新的需求,打开按钮的时候把 button 文字改成:快去登录。
装饰器模式
先拆分旧逻辑
javascript
function openModal() {
const modal = new Modal()
modal.style.display = 'block'
}
添加新逻辑
javascript
function changeBtnText() {
const open = document.getElementById('open')
open.innerHTML = '快去登录'
}
function disableButton() {
const open = document.getElementById('open');
open.setAttribute('disabled', true);
}
function changeBtnState() {
changeBtnText()
disableButton()
}
这样直接调用方法
javascript
document.getElementById('open').onclick = function() {
openModal();
changeBtnState()
}
如此一来,我们就实现了“只添加,不修改”的装饰器模式,使用 changeBtnState 的逻辑装饰了旧的按钮点击逻辑。以上是ES5中的实现,ES6中,我们可以以一种更加面向对象化的方式去写:
javascript
// 定义打开按钮
class OpenButton {
// 点击后展示弹框(旧逻辑)
onClick() {
const modal = new Modal()
modal.style.display = 'block'
}
}
// 定义按钮对应的装饰器
class Decorator {
// 将按钮实例传入
constructor(open_button) {
this.open_button = open_button
}
onClick() {
this.open_button.onClick()
// “包装”了一层新逻辑
this.changeButtonStatus()
}
changeButtonStatus() {
this.changeButtonText()
this.disableButton()
}
disableButton() {
const btn = document.getElementById('open')
btn.setAttribute("disabled", true)
}
changeButtonText() {
const btn = document.getElementById('open')
btn.innerText = '快去登录'
}
}
const openButton = new OpenButton()
const decorator = new Decorator(openButton)
document.getElementById('open').addEventListener('click', function() {
// openButton.onClick()
// 此处可以分别尝试两个实例的onClick方法,验证装饰器是否生效
decorator.onClick()
})