Js设计模式
创建型
工厂模式
let Factory = function (type,content){
if(this instanceof Factory){
let s = new this[type](content);
return s;
}else{
return new Factory(type,content);
}
}
Factory.prototype={
a:function(){},
b:function(){},
//...
}
省去了创建时的new步骤,对类进行封装
建造者模式
function Person(name,work){
let person = new Human();
person.name = new Named(name);
person.work = new Work(work);
return person;
}
过程化创建对象
原型模式
var vehiclePrototype = {
model:"car1",
getModel: function () {
console.log('车辆模具是:' + this.model);
}
};
var vehicle = Object.create(vehiclePrototype,{
"model":{
value:"car2"
}
});
vehicle.getModel();
将共有属性附加到原型上,其实继承也可以
单例模式
class DB{
static getInstance(){
if(!DB.instance){
DB.instance = new DB();
}
return DB.instance;
}
constructor() {
console.log(1);
}
}
let a1 = DB.getInstance();
let a2 = DB.getInstance();
类只实例化一次,减少开销
结构型
外观模式
function addEvent(dom,type,fn){
if(dom.addEventListener){
dom.addEventListener(type,fn,false);
}else if(dom.attachEvent){
dom.attachEvent('on'+type,fn);
}else{
dom['on'+type] = fn;
}
}
为复杂子系统接口提供一个高级的统一接口(封装来兼容功能)
适配器模式
class GooleMap {
show() {
console.log('渲染谷歌地图')
}
}
class BaiduMap {
display() {
console.log('渲染百度地图')
}
}
// 定义适配器类, 对BaiduMap类进行封装
class BaiduMapAdapter {
show() {
var baiduMap = new BaiduMap()
return baiduMap.display()
}
}
function render(map) {
if (map.show instanceof Function) {
map.show()
}
}
render(new GooleMap())
render(new BaiduMapAdapter())
用来做接口的适配
代理模式
class MyImage {
constructor() {
this.img = new Image()
document.body.appendChild(this.img)
}
setSrc(src) {
this.img.src = src
}
}
class ProxyImage {
constructor() {
this.proxyImage = new Image()
}
setSrc(src) {
let myImageObj = new MyImage()
myImageObj.img.src = 'file://xxx.png'
this.proxyImage.src = src
this.proxyImage.onload = function() {
myImageObj.img.src = src
}
}
}
var proxyImage = new ProxyImage()
proxyImage.setSrc('http://xxx.png')
为对象提供一个中间人来控制对对象的访问,如Es6中的Proxy
装饰着模式
let decorator = (type,fn)=>{
let input = document.querySelector("type");
if(typeof input.onclick === 'function'){
let oldFn = input.onclick;
input.onclick = function(){
oldFn();
fn();
}
}
}
decorator('tel_input',fn);
decorator('name_input',fn2);
在不改变对象的基础上,通过对其进行包装扩展
桥接者模式
function changeColor(dom,color,bg){
dom.style.color = color;
dom.style.background = bg;
}
强调抽离公共逻辑进行解耦
享元模式
var Book = function( id, title, author, genre, pageCount,publisherID, ISBN, checkoutDate, checkoutMember, dueReturnDate,availability ){
this.id = id;
this.title = title;
this.author = author;
this.genre = genre;
this.pageCount = pageCount;
this.publisherID = publisherID;
this.ISBN = ISBN;
this.checkoutDate = checkoutDate;
this.checkoutMember = checkoutMember;
this.dueReturnDate = dueReturnDate;
this.availability = availability;
};
Book.prototype = {
getTitle: function () {
return this.title;
},
getAuthor: function () {
return this.author;
},
getISBN: function (){
return this.ISBN;
},
updateCheckoutStatus: function( bookID, newStatus, checkoutDate , checkoutMember, newReturnDate ){
this.id = bookID;
this.availability = newStatus;
this.checkoutDate = checkoutDate;
this.checkoutMember = checkoutMember;
this.dueReturnDate = newReturnDate;
},
extendCheckoutPeriod: function( bookID, newReturnDate ){
this.id = bookID;
this.dueReturnDate = newReturnDate;
},
isPastDue: function(bookID){
var currentDate = new Date();
return currentDate.getTime() > Date.parse( this.dueReturnDate );
}
};
//如果使用每一个对象来管理一本书,迟早内存要寄
//把每本书自身信息设置为内在状态,外在状态为借阅信息
var Book = function ( title, author, genre, pageCount, publisherID, ISBN ) {
this.title = title;
this.author = author;
this.genre = genre;
this.pageCount = pageCount;
this.publisherID = publisherID;
this.ISBN = ISBN;
};
//为每一个ISBN的书创建一个单例,节省重复ISBN构建的对象
var BookFactory = (function () {
var existingBooks = {}, existingBook;
return {
createBook: function ( title, author, genre, pageCount, publisherID, ISBN ) {
existingBook = existingBooks[ISBN];
if ( !!existingBook ) {
return existingBook;
} else {
var book = new Book( title, author, genre, pageCount, publisherID, ISBN );
existingBooks[ISBN] = book;
return book;
}
}
};
});
// 外在状态单例,管理函数被一个外在对象所拥有而不是每一个实例对象
var BookRecordManager = (function () {
var bookRecordDatabase = {};
return {
addBookRecord: function ( id, title, author, genre, pageCount, publisherID, ISBN, checkoutDate, checkoutMember, dueReturnDate, availability ) {
var book = bookFactory.createBook( title, author, genre, pageCount, publisherID, ISBN );
bookRecordDatabase[id] = {
checkoutMember: checkoutMember,
checkoutDate: checkoutDate,
dueReturnDate: dueReturnDate,
availability: availability,
book: book
};
},
updateCheckoutStatus: function ( bookID, newStatus, checkoutDate, checkoutMember, newReturnDate ) {
var record = bookRecordDatabase[bookID];
record.availability = newStatus;
record.checkoutDate = checkoutDate;
record.checkoutMember = checkoutMember;
record.dueReturnDate = newReturnDate;
},
extendCheckoutPeriod: function ( bookID, newReturnDate ) {
bookRecordDatabase[bookID].dueReturnDate = newReturnDate;
},
isPastDue: function ( bookID ) {
var currentDate = new Date();
return currentDate.getTime() > Date.parse( bookRecordDatabase[bookID].dueReturnDate );
}
};
});
使用共享事物,尽可能减少内存开销。享元模式分为外部状态和内部状态,通过设置不同的外部状态使得相同的对象具备一些不同的特性,而内部状态设置为相同部分。
行为型
观察者模式
class Subject {
constructor() {
this.observers = []; // 观察者列表
}
// 添加
add(observer) {
this.observers.push(observer);
}
// 删除
remove(observer) {
let idx = this.observers.findIndex(item => item === observer);
idx > -1 && this.observers.splice(idx, 1);
}
// 通知
notify() {
for (let observer of this.observers) {
observer.update();
}
}
}
// 观察者类
class Observer {
constructor(name) {
this.name = name;
}
// 目标对象更新时触发的回调
update() {
console.log(`目标者通知我更新了,我是:${this.name}`);
}
}
// 实例化目标者
let subject = new Subject();
// 实例化两个观察者
let obs1 = new Observer('前端开发者');
let obs2 = new Observer('后端开发者');
// 向目标者添加观察者
subject.add(obs1);
subject.add(obs2);
// 目标者通知更新
subject.notify();
// 输出:
// 目标者通知我更新了,我是前端开发者
// 目标者通知我更新了,我是后端开发者
策略模式
var fnA = function(val) {
return val * 1
}
var fnB = function(val) {
return val * 2
}
var fnC = function (val) {
return val * 3
}
var calculate = function(fn, val) {
return fn(val)
}
console.log(calculate(fnA, 100))// 100
console.log(calculate(fnB, 100))// 200
console.log(calculate(fnC, 100))// 300
工具,算法类的封装
class OffLightState {
constructor(light) {
this.light = light
}
pressBtn() {
this.light.setState(this.light.weekLightState)
console.log('开启弱光')
}
}
class WeekLightState {
constructor(light) {
this.light = light
}
pressBtn() {
this.light.setState(this.light.strongLightState)
console.log('开启强光')
}
}
class StrongLightState {
constructor(light) {
this.light = light
}
pressBtn() {
this.light.setState(this.light.offLightState)
console.log('关闭电灯')
}
}
class Light {
constructor() {
this.offLightState = new OffLightState(this)
this.weekLightState = new WeekLightState(this)
this.strongLightState = new StrongLightState(this)
this.currentState = null
}
setState(newState) {
this.currentState = newState
}
init() {
this.currentState = this.offLightState
}
}
let light = new Light()
light.init()
var btn = document.getElementById('btn')
btn.onclick = function() {
light.currentState.pressBtn()
}
根据状态改变对象的行为,很容易增加新内容
架构篇
模块化、解耦、层次
MVC
model|view|controller
数据层
MVC.model = function(){
var M={};
M.data={
slideBar:[
{
//data1
},
{
//data2
}
]
}
M.conf={
slideBarCloseAnimate:false
}
return {
//接口(数据对象操作方法)方法
}
}();
视图层
MVC.view = function(){
var M = M.model;
var V = {
createSlideBar:function(){
//创建侧边栏
}
}
return function(v){
V[v]();
}
}();
控制层
MVC.ctrl = function(){
var V = MVC.view;
var M = MVC.model;
var C = {
initSlideBar:function(){
V('createSlideBar')
//其他功能如点击和动画功能
}
}
//遍历每个C的方法并执行
}();
但其实我们能发现视图层和数据层会耦合在一起。降低了视图创建的灵活性和复用性
MVP
model|view|Presenter
view不直接使用model的数据,而是通过presenter层实现对model层的访问。所有层次的交互都发生在presenter层。
数据层
MVP.model = function(){
var M = {};
M.data = {}
M.conf = {}
return {
getData:function(){},
setConf:function(){},
//...其他接口方法
}
}()
视图层
MVP.view = function(){
return //创建的模板html
}()
管理层
MVP.presenter = function(){
var V = MVP.view;
var M = MVP.model;
var C = {};//模块
return{
init:function(){
//遍历内部管理器
for(var i in C){
C[i]&&C[i](M,V,i);
}
}
}
}
var C = {
nav:function(M,V){
var data = M.getData('nav');
var tpl = V('创建模板的依据');
//通过一个通用方法处理data,tpl
//添加各种事件动画
}
}
MVVM
model|view|viewModel
量身定做一套视图模型,并在试图模型中添加创建属性和方法,为视图层绑定数据实现交互。直接通过创建视图实现页面需求。
视图层
<div class="first" data-bind="type:'slider',data:demo1"></div>
<div class="second" data-bind="type:'slider',data:demo2"></div>
<div class="third" data-bind="type:'progressbar',data:demo3"></div>
视图模型层
var VM = function(){
var method = {
//创建组件的策略方法
progressbar:function(dom,data){
//创建dom绑定数据,绑定事件,添加动画...
},
slider:function(dom,data){
}
}
function getBindData(dom){
var data = dom.getAttribute('data-bind');
return !!data&&(new Function(`return ({${data}}))`)();//这里实现了数据层数据传输到视图层
}
return function(){
//遍历所有UI组件
//根据自定义属性中的组件类型,渲染该组件
ctx=getBindData(dom[i])
method[dom.type]&&mthod[dom.type](doms[i],ctx)
}();
}
数据层
var demo1={
position:60,
totle:200
}
window.onload=function(){
VM();
}