百色住房和城乡建设部网站,wordpress 漂浮窗口,江都建设局网站,深圳推广概念
设计模式是怎么解决问题的一种方案
常见的设计模式
单例模式
概念#xff1a;保证一个类仅有一个实例#xff0c;并提供一个访问它的全局访问点。 应用#xff1a;项目封装个websocket用于大屏#xff0c;redux#xff0c;vuex都应用了单例模式的思想#xff1b…概念
设计模式是怎么解决问题的一种方案
常见的设计模式
单例模式
概念保证一个类仅有一个实例并提供一个访问它的全局访问点。 应用项目封装个websocket用于大屏reduxvuex都应用了单例模式的思想现在很多第三方库都是单例模式多次引用只会使用同一个对象如jquery、lodash、moment 实现先判断实例存在与否如果存在则直接返回如果不存在就创建了再返回这就确保了一个类只有一个实例对象
// 定义一个类
function Singleton(name) {this.name name;this.instance null;
}
// 原型扩展类的一个方法getName()
Singleton.prototype.getName function() {console.log(this.name)
};
// 获取类的实例
Singleton.getInstance function(name) {if(!this.instance) {this.instance new Singleton(name);}return this.instance
};// 获取对象1
const a Singleton.getInstance(a);
// 获取对象2
const b Singleton.getInstance(b);
// 进行比较
console.log(a b);//true工厂模式
概念不暴露创建对象的具体逻辑而是将逻辑封装在一个函数中那么这个函数就可以被视为一个工厂。 工厂模式根据抽象程度的不同可以分为 简单工厂模式Simple Factory用一个工厂对象创建同一类对象类的实例. function Factory(career) {function User(career, work) {this.career career this.work work}let workswitch(career) {case coder:work [写代码, 修Bug] return new User(career, work)breakcase boss:work [喝茶, 开会, 审批文件]return new User(career, work)break}
}
let coder new Factory(coder)
console.log(coder)
let boss new Factory(boss)
console.log(boss)工厂方法模式Factory Method工厂方法模式跟简单工厂模式差不多但是把具体的产品放到了工厂函数的prototype中. // 工厂方法
function Factory(career){if(this instanceof Factory){var a new this[career]();return a;}else{return new Factory(career);}
}
// 工厂方法函数的原型中设置所有对象的构造函数
Factory.prototype{coder: function(){this.careerName 程序员this.work [写代码, 修Bug] },hr: function(){this.careerName HRthis.work [招聘, 员工信息管理]}
}
let coder new Factory(coder)
console.log(coder)
let hr new Factory(hr)
console.log(hr)抽象工厂模式Abstract Factory简单工厂模式和工厂方法模式都是直接生成实例但是抽象工厂模式不同抽象工厂模式并不直接生成实例 而是用于对产品类簇的创建。 通俗点来讲就是简单工厂和工厂方法模式的工作是生产产品那么抽象工厂模式的工作就是生产工厂的 let CareerAbstractFactory function(subType, superType) {// 判断抽象工厂中是否有该抽象类if (typeof CareerAbstractFactory[superType] function) {// 缓存类function F() {}// 继承父类属性和方法F.prototype new CareerAbstractFactory[superType]()// 将子类的constructor指向父类subType.constructor subType;// 子类原型继承父类subType.prototype new F()} else {throw new Error(抽象类不存在)}
}
//由于JavaScript中并没有抽象类的概念只能模拟可以分成四部分
//用于创建抽象类的函数
//抽象类
//具体类
//实例化具体类
//上面代码中CareerAbstractFactory就是一个抽象工厂方法该方法在参数中传递子类和父类在方法体内部实现了子类对父类的继承工厂模式适用场景如下
如果你不想让某个子系统与较大的那个对象之间形成强耦合而是想运行时从许多子系统中进行挑选的话那么工厂模式是一个理想的选择将new操作简单封装遇到new的时候就应该考虑是否用工厂模式需要依赖具体环境创建不同实例这些实例都有相同的行为,这时候我们可以使用工厂模式简化实现的过程同时也可以减少每种对象所需的代码量有利于消除对象间的耦合提供更大的灵活性
策略模式
概念定义一系列的算法把它们一个个封装起来目的就是将算法的使用与算法的实现分离开来。 一个基于策略模式的程序至少由两部分组成 策略类可变策略类封装了具体的算法并负责具体的计算过程 环境类不变接受客户的请求随后将请求委托给某一个策略类
var obj {A: function(salary) {return salary * 4;},B : function(salary) {return salary * 3;},C : function(salary) {return salary * 2;}
};
var calculateBouns function(level,salary) {return obj[level](salary);
};
console.log(calculateBouns(A,10000)); // 40000策略模式的优点有如下
策略模式利用组合委托等技术和思想有效的避免很多if条件语句策略模式提供了开放-封闭原则使代码更容易理解和扩展策略模式中的代码可以复用
代理模式
概念给某一个对象提供一个代理对象并由代理对象控制对原对象的引用。
在ES6中存在proxy构建函数能够让我们轻松使用代理模式
const proxy new Proxy(target, handler);而按照功能来划分javascript代理模式常用的有 缓存代理缓存代理可以为一些开销大的运算结果提供暂时的存储在下次运算时如果传递进来的参数跟之前一致则可以直接返回前面存储的运算结果。 //缓存代理可以为一些开销大的运算结果提供暂时的存储在下次运算时如果传递进来的参数跟之前一致则可以直接返回前面存储的运算结果
var proxyMult (function () {var cache {};return function () {var args Array.prototype.join.call(arguments, ,);if (args in cache) {return cache[args];}return (cache[args] mult.apply(this, arguments));};
})();proxyMult(1, 2, 3, 4); // 输出:24
proxyMult(1, 2, 3, 4); // 输出:24虚拟代理虚拟代理把一些开销很大的对象延迟到真正需要它的时候才去创建。 常见的就是图片预加载功能 // 图片本地对象负责往页面中创建一个img标签并且提供一个对外的setSrc接口
let myImage (function(){let imgNode document.createElement( img );document.body.appendChild( imgNode );return {//setSrc接口外界调用这个接口便可以给该img标签设置src属性setSrc: function( src ){imgNode.src src;}}
})();
// 代理对象负责图片预加载功能
let proxyImage (function(){// 创建一个Image对象用于加载需要设置的图片let img new Image;img.onload function(){// 监听到图片加载完成后给被代理的图片本地对象设置src为加载完成后的图片myImage.setSrc( this.src );}return {setSrc: function( src ){// 设置图片时在图片未被真正加载好时以这张图作为loading提示用户图片正在加载myImage.setSrc( https://img.zcool.cn/community/01deed576019060000018c1bd2352d.gif );img.src src;}}
})();proxyImage.setSrc( https://xxx.jpg );应用场景 现在的很多前端框架或者状态管理框架都使用代理模式用与监听变量的变化。 使用代理模式代理对象的访问的方式一般又被称为拦截器比如我们在项目中经常使用 Axios 的实例来进行 HTTP 的请求使用拦截器 interceptor 可以提前对 请求前的数据 服务器返回的数据进行一些预处理。 以及上述应用到的缓存代理和虚拟代理。
中介者模式
通过一个中介者对象其他所有的相关对象都通过该中介者对象来通信当其中的一个对象发生改变时只需要通知中介者对象即可。
通过中介者模式可以解除对象与对象之间的紧耦合关系
装饰者模式
在原有方法维持不变在原有方法上再挂载其他方法来满足现有需求。
观察者模式
观察者模式定义了对象间的一种一对多的依赖关系当一个对象的状态发生改变时所有依赖于它的对象都将得到通知并自动更新。 观察者模式属于行为型模式行为型模式关注的是对象之间的通讯观察者模式就是观察者和被观察者之间的通讯。
// 被观察者模式
class Subject {constructor() {this.observerList [];}addObserver(observer) {this.observerList.push(observer);}removeObserver(observer) {const index this.observerList.findIndex(o o.name observer.name);this.observerList.splice(index, 1);}notifyObservers(message) {const observers this.observeList;observers.forEach(observer observer.notified(message));}
}//观察者
class Observer {constructor(name, subject) {this.name name;if (subject) {subject.addObserver(this);}}notified(message) {console.log(this.name, got message, message);}
}
//使用
const subject new Subject();
const observerA new Observer(observerA, subject);
const observerB new Observer(observerB);
subject.addObserver(observerB);
subject.notifyObservers(Hello from subject);
subject.removeObserver(observerA);
subject.notifyObservers(Hello again);发布订阅模式
发布-订阅是一种消息范式消息的发送者称为发布者不会将消息直接发送给特定的接收者称为订阅者。而是将发布的消息分为不同的类别无需了解哪些订阅者如果有的话可能存在。
// 发布订阅中心
class PubSub {constructor() {this.messages {};this.listeners {};}// 添加发布者publish(type, content) {const existContent this.messages[type];if (!existContent) {this.messages[type] [];}this.messages[type].push(content);}// 添加订阅者subscribe(type, cb) {const existListener this.listeners[type];if (!existListener) {this.listeners[type] [];}this.listeners[type].push(cb);}// 通知notify(type) {const messages this.messages[type];const subscribers this.listeners[type] || [];subscribers.forEach((cb, index) cb(messages[index]));}
}//发布者代码
class Publisher {constructor(name, context) {this.name name;this.context context;}publish(type, content) {this.context.publish(type, content);}
}//订阅者代码
class Subscriber {constructor(name, context) {this.name name;this.context context;}subscribe(type, cb) {this.context.subscribe(type, cb);}
}//使用代码
const TYPE_A music;
const TYPE_B movie;
const TYPE_C novel;const pubsub new PubSub();const publisherA new Publisher(publisherA, pubsub);
publisherA.publish(TYPE_A, we are young);
publisherA.publish(TYPE_B, the silicon valley);
const publisherB new Publisher(publisherB, pubsub);
publisherB.publish(TYPE_A, stronger);
const publisherC new Publisher(publisherC, pubsub);
publisherC.publish(TYPE_C, a brief history of time);const subscriberA new Subscriber(subscriberA, pubsub);
subscriberA.subscribe(TYPE_A, res {console.log(subscriberA received, res)
});
const subscriberB new Subscriber(subscriberB, pubsub);
subscriberB.subscribe(TYPE_C, res {console.log(subscriberB received, res)
});
const subscriberC new Subscriber(subscriberC, pubsub);
subscriberC.subscribe(TYPE_B, res {console.log(subscriberC received, res)
});pubsub.notify(TYPE_A);
pubsub.notify(TYPE_B);
pubsub.notify(TYPE_C);//发布者和订阅者需要通过发布订阅中心进行关联发布者的发布动作和订阅者的订阅动作相互独立无需关注对方消息派发由发布订阅中心负责。发布订阅、观察者模式区别
在观察者模式中观察者是知道Subject的Subject一直保持对观察者进行记录。然而在发布订阅模式中发布者和订阅者不知道对方的存在。它们只有通过消息代理进行通信。在发布订阅模式中组件是松散耦合的正好和观察者模式相反。观察者模式大多数时候是同步的比如当事件触发Subject就会去调用观察者的方法。而发布-订阅模式大多数时候是异步的使用消息队列