1. 什么是结构型模式
结构型模式主要用于处理类和对象的组合,对应思维导图:
2. 外观模式: Facade Pattern
对接口二次封装隐藏其复杂性,并简化其使用。
外观模式包含如下角色:
Facade
: 外观角色SubSystem
: 子系统角色
使用时机
当我们将系统分成多个子系统时,我们会降低代码复杂性。编程时的最佳实践是最小化子系统之间的通信和依赖关系。实现这一目标的一个好方法是引入一个facade
对象,为子系统提供单一且统一的接口。
1. 跨浏览器监听事件
要保证处理事件的代码在大多数浏览器下一致运行,需要关注冒泡阶段。
在做跨浏览器网站时,你已经不经意间使用了外观模式:
var addMyEvent = function( el,ev,fn ){
if( el.addEventListener ){//存在DOM2级方法,则使用并传入事件类型、事件处理程序函数和第3个参数false(表示冒泡阶段)
el.addEventListener( ev,fn, false );
}else if(el.attachEvent){ // 为兼容IE8及更早浏览器,注意事件类型必须加上"on"前缀
el.attachEvent( "on" + ev, fn );
}else{
el["on" + ev] = fn;//其他方法都无效,默认采用DOM0级方法,使用方括号语法将属性名指定为事件处理程序
}
};
2. jQuery $(document).ready(..)
我们都熟悉$(document).ready(..)
。在源码中,这实际上是一个被调用的方法提供的bindReady()
:
加载事件共用两种方法
:window.onload()
和$(document).ready()
bindReady: function() {
...
if ( document.addEventListener ) {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
// A fallback to window.onload, that will always work
window.addEventListener( "load", jQuery.ready, false );
// If IE event model is used
} else if ( document.attachEvent ) {
document.attachEvent( "onreadystatechange", DOMContentLoaded );
// A fallback to window.onload, that will always work
window.attachEvent( "onload", jQuery.ready );
Facade
外观模式大量应用于 jQuery
库以让其更容易被使用。譬如我们使用
jQuery
的$(el).css()
或 $(el).animate()
等方法 。
使我们不必手动在jQuery
内核中调用很多内部方法以便实现某些行为,也同时避免了手动与 DOM API
交互。
类似的还有
D3.js
3. 适配器模式: Adapter Pattern
- 传统:适配两个及以上类接口不兼容的问题
JS
: 可额外适配两个及以上代码库、前后端数据等。
使用时机
通常使用适配器的情况:
- 需要集成新组件并与应用程序中的现有组件一起工作。
- 重构,程序的哪些部分用改进的接口重写,但旧代码仍然需要原始接口。
1. jQuery.fn.css()
规范化显示
// Cross browser opacity:
// opacity: 0.9; Chrome 4+, FF2+, Saf3.1+, Opera 9+, IE9, iOS 3.2+, Android 2.1+
// filter: alpha(opacity=90); IE6-IE8
// Setting opacity
$( ".container" ).css( { opacity: .5 } );
// Getting opacity
var currentOpacity = $( ".container" ).css('opacity');
内部实现为:
get: function( elem, computed ) {
return ropacity.test( (
computed && elem.currentStyle ?
elem.currentStyle.filter : elem.style.filter) || "" ) ?
( parseFloat( RegExp.$1 ) / 100 ) + "" :
computed ? "1" : "";
},
set: function( elem, value ) {
var style = elem.style,
currentStyle = elem.currentStyle,
opacity = jQuery.isNumeric( value ) ?
"alpha(opacity=" + value * 100 + ")" : "",
filter = currentStyle && currentStyle.filter || style.filter || "";
style.zoom = 1;
// 如果将不透明度设置为1,则移除其他過濾器
//exist - attempt to remove filter attribute #6652
if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
style.removeAttribute( "filter" );
if ( currentStyle && !currentStyle.filter ) {
return;
}
}
// otherwise, set new filter values
style.filter = ralpha.test( filter ) ?
filter.replace( ralpha, opacity ) :
filter + " " + opacity;
}
};
2. Vue
中的computed
yck - 《前端面试之道》
在 Vue
中,我们其实经常使用到适配器模式。
比如父组件传递给子组件一个时间戳属性,组件内部需要将时间戳转为正常的日期显示,一般会使用 computed
来做转换这件事情,这个过程就使用到了适配器模式。