桥接模式定义
桥接模式是指在系统沿着多个维度变化的同时,又不增加其复杂度并已达到解耦。
桥接模式应用
事件监听器回调函数
桥接模式最常见和实际的应用场合之一就是事件监听器回调函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>bridage</title>
</head>
<body>
<ul>
<li data-id="1" >1</li>
<li data-id="2" >2</li>
</ul>
<p id="content">
</p>
<script>
let lis = document.querySelectorAll('li');
for(let i=0;i<lis.length;i++){
lis[i].addEventListener('click',getUserById);
}
function getUserById(event){
let id = this.dataset.id;
let xhr = new XMLHttpRequest;
xhr.open('GET',`/user/${id}`,true);
xhr.responseType = 'json';
xhr.onreadystatechange = function(){
if(xhr.readyState ===4 && xhr.status == 200){
let user = xhr.response;
document.getElementById('content').innerHTML = user.name;
}
}
xhr.send();
}
</script>
</body>
</html>
上面的demo是实现点击li标签后发送请求获取对应id的name并写入content节点的操作,主要实现在getUserById方法中。这个getUserById方法存在的两个问题,一是依赖this,二是含有操作dom的操作。
如果要通过桥接模式对其进行改造,首先要对getUserById方法进行改造,可以把id通过参数传进来,并且将dom操作部分通过callback传进来,解除对this和dom的依赖。
function getUserById(id,callback){
let id = this.dataset.id;
let xhr = new XMLHttpRequest;
xhr.open('GET',`/user/${id}`,true);
xhr.responseType = 'json';
xhr.onreadystatechange = function(){
if(xhr.readyState ===4 && xhr.status == 200){
let user = xhr.response;
callback(user);
}
}
xhr.send();
}
然后实现一个桥接的方法来将getUserById方法和事件监听联系起来。
function addBridage(){
let id = this.dataset.id;
getUserById(id,function(user){
document.getElementById('content').innerHTML = user.name;
});
}
完整代码如下:
<script>
let lis = document.querySelectorAll('li');
for(let i=0;i<lis.length;i++){
lis[i].addEventListener('click',addBridage);
}
function getUserById(event){
let id = this.dataset.id;
let xhr = new XMLHttpRequest;
xhr.open('GET',`/user/${id}`,true);
xhr.responseType = 'json';
xhr.onreadystatechange = function(){
if(xhr.readyState ===4 && xhr.status == 200){
let user = xhr.response;
document.getElementById('content').innerHTML = user.name;
}
}
xhr.send();
}
function addBridage(){
let id = this.dataset.id;
getUserById(id,function(user){
document.getElementById('content').innerHTML = user.name;
});
}
function getUserById(id,callback){
let xhr = new XMLHttpRequest;
xhr.open('GET',`/user/${id}`,true);
xhr.responseType = 'json';
xhr.onreadystatechange = function(){
if(xhr.readyState ===4 && xhr.status == 200){
let user = xhr.response;
callback(user);
}
}
xhr.send();
}
</script>
多维变化
桥接模式对于多维变化也同样适用。一个对象或者功能有多个维度,比如canvas画一个图形,图形包含了颜色,位置等,其中颜色和位置就是两个不同的维度,现在希望它们可以单独的变化而不互相影响。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>html</title>
<style>
* {
margin:0;
padding:0;
}
canvas{
border:1px solid #000;
}
</style>
</head>
<body>
<canvas id="canvas" width="600" height="600"></canvas>
<script>
//形状 颜色 坐标
function Position(x,y) {
this.x=x;
this.y=y;
}
function Color(color) {
this.color=color;
}
function Ball(x,y,color) {
this.position=new Position(x,y);
this.color=new Color(color);
}
Ball.prototype.draw=function () {
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.arc(this.position.x,this.position.y,100,0,2*Math.PI);
ctx.fillStyle = this.color.color;
ctx.fill();
}
new Ball(300,300,'red').draw();
</script>
</body>
</html>
上面代码将位置和颜色分别写成两个类,两个类之间互不影响,通过circle类作为桥将两个类连接起来。
小结
- 桥接模式最主要的特点是将实现层(如元素的绑定事件)与抽象层(如修饰页面UI逻辑)解耦分离,使两部分可以独立变化。
- 通过桥接模式实现的解耦,使实现层与抽象层分开处理,避免需求的改变造成对象内部的修改,体现了面向对象对拓展的开放和对修改的封闭。
- 在代码开发中,注意对相同的逻辑做抽象提取处理,这样可以使代码更简洁,同时提高重用率和可读性。