🎉工厂模式
工厂模式就是降低耦合将重复代码进行提取。
- 如果存在足够多的相同的属性和方法,需要进行提取,将公共的类进行包装,并且不允许实例化。
- 父类是一个抽象类,并且不能实例
- 子类实现自身的实例方法
function BicycleF(name){
this.name = name
this.method = function(){
return this.name
}
}
Bicycle.prototype = {
constructor: BicycleF,
sellBicycle:function(){
//这里是子类的方法
var bicycle = this.createBicycle()
bicycle.a()
bicycle.b()
return bicycle
},
createBicycle:function(){
throw new Error('父类不允许进行实例化,需要使用子类的方法')
}
}
//子类继承父类
function extend(Sub, Sup){
var F = function(){}
F.prototype = Suo.prototype
Sub.prototype = new F()
Sub.prototype.constructor = Sub
Sub.sup = Sup.prototype
}
//创建子类
function BicycleS(name){
BicycleF.call(this.name)
}
extend(BicycleS, BicycleF)
BicycleS.prototype.createBicycle = function(){
var a = function(){
console.log("实现子类创建a")
}
var b = function(){
console.log("实现子类创建b")
}
return {
a,
b
}
}
🎉单例模式
划分命名空间,并且将属性和方法组织在一起的一种方式,只是实例化一次,并且对于实例对象为同一对象。
function Singleton(name){
this.name = name
}
Singleton.prototype.getName = function(){
console.log(this,name)
}
//这里是实现单例模式的方法
var getInstance = (
function(){
let instance
return function(name){
if(!instance){
instance = new Singleton(name)
}
return instance
}
}
)()
//或者放在构造函数的静态属性上
Singleton.getInstance = function(name){
if(!this.instance){
this.instance = new Singleton()
}
return this.instance
}
var b = getInstance('zhangsan')
var b = Singleton.getInstance('zhangsan')
var a = getInstance('lisi')
console.log(a,b)
console.log(a === b) // true
🎇应用
这样点击按钮只会创建一个div标签,不会重复的创建。
//应用
var btn = document.getElementById('btn')
var creatDiv = function(){
var div = document.createElement('div')
div.innerText = '我是单例创建的div,只会生成一次!!'
document.body.appendChild(div)
div.style.display = 'none'
return div
}
//这里就是单例模式的核心思想,当res本来是存在的话,就直接返回,不会再进行重新的创建。
var creatSingleone = function(fn){
var res
return function(){
//这里的this,是为了将fn的只想到btn上
return res || (res = fn.call(this,arguments))
}
}
btn.onclick = function(){
var div = creatSingleone(creatDiv)
div.style.display = "block"
}
🎉策略模式
在JS中要保证开放封闭原则,对于扩展开放,对于修改封闭,降低代码的重复度。
策略模式是一种行为设计模式,定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。
相当于我们只有需要对于strategies对象进行不断的配置,建立映射的关系即可,这样就可以将calculateBonus函数进行固定。
这里有篇文章讲的很棒:juejin.cn/post/711345…
//策略模式就是将现有的逻辑进行整理进行提取
//这里就相当于策略模式,可以在这个对象中进行添加,而不需要在动用底下的逻辑
var strategies = {
S:function(salary){
return salary * 3
},
A:function(salary){
return salary * 2
},
B:function(salary){
return salary * 1
}
}
var calculateBonus = function(performanceLevel, salary){
return strategies[performanceLevel](salary)
}
console.log(calculateBonus('S', 10000))
🎉发布订阅模式--一对多之间的关系
在发布订阅中有三个部分发布订阅模式中有三个角色,发布者 Publisher
,事件调度中心 Event Channel
,订阅者 Subscriber
,发布-订阅模式用来处理不同系统组件的信息交流,即使这些组件不知道对方的存在
在Vue中自定义事件和全局事件总线就是使用的发布和订阅的模式。
class PubSub {
constructor() {
// 事件中心
// 存储格式: warTask: [], routeTask: []
// 每种事件(任务)下存放其订阅者的回调函数
this.events = {}
}
// 订阅方法,就是将事件放进events
subscribe(type, cb) {
if (!this.events[type]) {
this.events[type] = [];
}
this.events[type].push(cb);
}
// 发布方法,就是将events中的事件进行执行
publish(type, ...args) {
if (this.events[type]) {
this.events[type].forEach(cb => cb(...args))
}
}
// 取消订阅方法
unsubscribe(type, cb) {
if (this.events[type]) {
const cbIndex = this.events[type].findIndex(e=> e === cb)
if (cbIndex != -1) {
this.events[type].splice(cbIndex, 1);
}
}
if (this.events[type].length === 0) {
delete this.events[type];
}
}
unsubscribeAll(type) {
if (this.events[type]) {
delete this.events[type];
}
}
}
// 创建一个事件调度中心
let pubsub = new PubSub();
// 订阅warTask任务
pubsub.subscribe('warTask', function (taskInfo){
console.log("信息:" + taskInfo);
})
// 订阅routeTask任务
pubsub.subscribe('routeTask', function (taskInfo) {
console.log("信息:" + taskInfo);
});
// 订阅allTask任务
pubsub.subscribe('allTask', function (taskInfo) {
console.log("信息:" + taskInfo);
});
// 发布任务
pubsub.publish('warTask', "这里是订阅了warTask任务的会触发");
pubsub.publish('allTask', "这里是订阅了allTask任务的会触发");
pubsub.publish('routeTask', "这里是订阅了routeTask任务的会触发");
🎉观察者模式--一对多之间的关系
-
目标对象
Subject
:- 维护观察者列表
observerList
———— 存放观察者列表 - 定义添加观察者的方法
- 当自身发生变化后,通过调用自己的
notify
方法依次通知每个观察者执行update
方法
- 维护观察者列表
-
观察者
Observer
需要实现update
方法,供目标对象调用。update
方法中可以执行自定义的业务逻辑
很有意思的小文章:juejin.cn/post/705544…
class Observer {
constructor(name) {
this.name = name;
}
update({taskType, taskInfo}) {
// 假设任务分为日常route和战斗war
if (taskType === "route") {
console.log(`${this.name}不需要日常任务`);
return;
}
this.goToTaskHome(taskInfo);
}
goToTaskHome(info) {
console.log(`${this.name}去任务大殿抢${info}任务`);
}
}
class Subject {
constructor() {
this.observerList = []
}
addObserver(observer) {
this.observerList.push(observer);
}
notify(task) {
console.log("发布五星任务");
this.observerList.forEach(observer => observer.update(task))
}
}
const subject = new Subject();
const stu1 = new Observer("弟子1");
const stu2 = new Observer("弟子2");
// stu1 stu2 购买五星任务通知权限
subject.addObserver(stu1);
subject.addObserver(stu2);
// 任务殿发布五星战斗任务
const warTask = {
taskType: 'war',
taskInfo: "猎杀时刻"
}
// 任务大殿通知购买权限弟子
subject.notify(warTask);
// 任务殿发布五星日常任务
const routeTask = {
taskType: 'route',
taskInfo: "种树浇水"
}
subject.notify(routeTask);
🎉适配器模式
在使用一个已经存在的类,但是如果他的接口实现的方法不满足你的要求不同时,就可以使用适配器模式。其实站在软件设计的角度,在开发前期应该考虑好,而不是一开始就使用适配器模式来实现,这样是不合理的。
适配器模式往往存在于软件开发后期两个不兼容接口,并且不易修改,可以使用适配器模式来解决。
var getBeijingMap = function(){
var Beijing = [
{name:'朝阳', id:1},
{name:'海淀', id:12}
]
return Beijing
}
var render = function(fn){
console.log(JSON.stringify(fn()))
}
render(getBeijingMap)
//[{"name":"朝阳", "id":"11"},{"name":"海淀"},"id":"12"]
//当我需要另外一种格式并且不能进行修改原来的代码时
//这里就是适配器
var addressAdapter function(oldAdress){
var adress = {},oldAdress = oldAdress(), item
or(var i = 0; i < oldAdress.length; i++){
item = oldAdress[i]
adress[item.name] = item.id
}
return function(){
return adress
}
}
render(addressAdapter(getBeijingMap))
//{"朝阳":"11","海淀":"12"}