【设计模式】

创建型设计模式
单例模式:保证一个类只有一个实例,并提供一个全局访问点。
Vue中的axios实例(我们对axios进行请求拦截和响应拦截,多次调用封装好的axios但是仅设置一次,封装好的axios导出就是一个单例)、全局态管理 store

var createMask = function(){
  var mask;
  return function(){
       return mask || ( mask = document.body.appendChild( document.createElement('div') ) )
  }
}()


工厂模式:定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型。

function CreatePerson(name,age,sex) {
     var obj = new Object();
     obj.name = name;
     obj.age = age;
     obj.sex = sex;
     obj.sayName = function(){
         return this.name;
     };
     return obj;
}
var p1 = new CreatePerson("longen",'28','男');
var p2 = new CreatePerson("tugenhua",'27','女');


结构型设计模式
装饰者模式:在不改变原对象的基础上,通过对其进行包装拓展(添加属性和方法)使原有对象更加满足用户的复杂需求。

let decorate = function(input, fn){
    let input = document.getElementById("input");
    if(typeof input.onclick ===  "function"){
        var oldClickFn = input.onclick;
        input.onclick = function(){
            oldClickFn();
            fn();
        }
    }
    else{
        input.onclick = fn();
    }
}


代理模式:由于一个对象不能直接应用另一个对象,所以需要通过代理对象其搭配中介作用
行为型设计模式
观察者模式:定义了一种依赖关系, 解决了主体对象与观察者之间功能的耦合                           vue中的computed   事件绑定    watch监听

var Observer = (function(){
   var _message = {};
    return {
        //注册接口
        regist: function(type, fn){
            //如果消息此消息不存在则应该创建一个消息类型
            if(typeof _message[type] === 'undefined'){
                //将动作推入到该消息对一个的动作执行队列中
                _message[type] = [fn];
            }else{
                _message[type].push(fn);
            }
        },
        //发布信息接口
        fire: function(type, args){
            //如果该消息没有被注册,则返回
            if(!_message[type]){
                return;
            }
            //定义消息信息
            var events={
                type: type,
                args: args || {}
            }
            for(let i=0; _message[type].length; i++){
                _message[type][i].call(this, events);
            }
        },
        //移除信息接口
        remove: function(){
            //如果消息队列存在
            if(_message[type] instanceof Array){
                //从最后一个消息动作开始遍历
                for(let i=_message[type].length-1; i>=0; i--){
                    //如果存在该动作则移除相应动作
                    _message[type][i] === fn && _message[type].splice(i, 1);
                }
            }
        }
    }
})();
//订阅一条消息
Observer.regist('test', function(e){
    console.log(e.type, e.args.msg);
});
//发布上条消息
Observer.fire('test', {msg: '发布成功啦~'});


适配器模式:

在程序里适配器模式也经常用来适配 2 个接口, 比如你现在正在用一个自定义的 js 库. 里面有个根据 id 获取节点的方法 $id(). 有天你觉得 jquery 里的 $实现得更酷, 但你又不想让你的工程师去学习新的库和语法. 那一个适配器就能让你完成这件事情.

$id = function( id ){
  return jQuery( '#' + id )[0];
}



代理模式

正向代理:

反向代理(nginx)
反向代理是基于服务端的,不对外暴露真实的服务器;

class Store extends Factory {
  constructor() {
    super();
  }

 

  sall(): string {
    this.total--;
    return "领克03"
  }

  afterSale(): void {
    console.log("售后服务!");
  }
}

class Custoemr {
  shop(car: string): void {
    console.log(`买了一辆${car}`);
  }
}

// 实例化出一个做代理的对象
const lingke = new Store();

// 实例化一个 使用代理对象的对象
const zs = new Custoemr();

zs.shop(lingke.sall());


桥接模式

桥接模式(Bridge)将抽象部分与它的实现部分分离,使它们都可以独立地变化。

class Speed {            // 运动模块
  constructor(x, y) {
    this.x = x
    this.y = y
  }
  run() {  console.log(`运动起来 ${this.x} + ${this.y}`)  }
}

class Color {            // 着色模块
  constructor(cl) {
    this.color = cl
  }
  draw() {  console.log(`绘制颜色 ${this.color}`)  }
}

class Speak {
  constructor(wd) {
    this.word = wd
  }
  say() {  console.log(`说话 ${this.word}`)  }
}

class Ball {                     // 创建球类,可以着色和运动
  constructor(x, y, cl) {
    this.speed = new Speed(x, y)
    this.color = new Color(cl)
  }
  init() {
    this.speed.run()
    this.color.draw()
  }
}

class Man {                    // 人类,可以运动和说话
  constructor(x, y, wd) {
    this.speed = new Speed(x, y)
    this.speak = new Speak(wd)
  }
  init() {
    this.speed.run()
    this.speak.say()
  }
}

const man = new Man(1, 2, 'hehe?')
man.init()                                // 运动起来 1 + 2      说话 hehe?


外观模式

为一组复杂的子系统接口提供一个更高级的统一接口,通过这个接口使得对子系统接口的访问更容易

function addEventToDOM(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 ;
    }
}


访问者模式
访问者模式的思想就是在不改变操作对象的同时,为它添加新的操作方法,以实现对操作对象的访问。我们知道,call 和 apply 的作用就是更改函数执行时的作用域,这正是访问者模式的精髓。通过 call、apply 这两种方式我们就可以让某个对象在其它作用域中运行。

// 访问者模式:数组方法封装
var Visitor = (function() {
    return {
        splice: function() {
            var args = Array.prototype.splice.call(arguments, 1);
            return Array.prototype.splice.apply(arguments[0], args);
        },
        push: function() {
            var len = arguments[0].length || 0;
            var args = this.splice(arguments, 1);
            arguments[0].length = len + arguments.length - 1;
            return Array.prototype.push.apply(arguments[0], args);
        },
        pop: function() {
            return Array.prototype.pop.apply(arguments[0]);
        }
    }
})();

var a = new Object();
Visitor.push(a,1,2,3,4);//4
Visitor.push(a,4,5,6);//7
Visitor.pop(a);//6
Visitor.splice(a,2)//[3,4,4,5];


策略模式
1. Context :封装上下文,根据需要调用需要的策略,屏蔽外界对策略的直接调用,只对外提供一个接口,根据需要调用对应的策略;

2. Strategy :策略,含有具体的算法,其方法的外观相同,因此可以互相代替;

3. StrategyMap :所有策略的合集,供封装上下文调用;

export const StrategyMap = {
    // Strategy 1: 将文件大小(bit)转化为 KB
    bitToKB: val => {
        const num = Number(val)
        return isNaN(num) ? val : (num / 1024).toFixed(0) + 'KB'
    },
    // Strategy 2: 将文件大小(bit)转化为 MB 
    bitToMB: val => {
        const num = Number(val)
        return isNaN(num) ? val : (num / 1024 / 1024).toFixed(1) + 'MB'
    }
}
 
// Context: 生成el表单 formatter
const strategyContext = function (type, rowKey) {
    return function (row, column, cellValue, index) {
        return StrategyMap[type](row[rowKey])
    }
}

模板方式模式
模板方法模式由两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。

var Beverage = function(){};

Beverage.prototype.boilWater = function(){
    console.log( '把水煮沸' );
};

Beverage.prototype.brew = function(){
    throw new Error( '子类必须重写brew方法' );
};

Beverage.prototype.pourInCup = function(){
    throw new Error( '子类必须重写pourInCup方法' );
};

Beverage.prototype.addCondiments = function(){
    throw new Error( '子类必须重写addCondiments方法' );
};

Beverage.prototype.customerWantsCondiments = function(){
    return true;    // 默认需要调料
};

Beverage.prototype.init = function(){
    this.boilWater();
    this.brew();
    this.pourInCup();
    if ( this.customerWantsCondiments() ){    // 如果挂钩返回true,则需要调料
        this.addCondiments();
    }
};


var CoffeeWithHook = function(){};

CoffeeWithHook.prototype = new Beverage();

CoffeeWithHook.prototype.brew = function(){
    console.log( '用沸水冲泡咖啡' );
};

CoffeeWithHook.prototype.pourInCup = function(){
    console.log( '把咖啡倒进杯子' );
};

CoffeeWithHook.prototype.addCondiments = function(){
    console.log( '加糖和牛奶' );
};

CoffeeWithHook.prototype.customerWantsCondiments = function(){
    return window.confirm( '请问需要调料吗?' );
};

var coffeeWithHook = new CoffeeWithHook();
coffeeWithHook.init();
var Beverage = function( param ){

    var boilWater = function(){
        console.log( '把水煮沸' );
    };

    var brew = param.brew || function(){
        throw new Error( '必须传递brew方法' );
    };

    var pourInCup = param.pourInCup || function(){
        throw new Error( '必须传递pourInCup方法' );
    };

    var addCondiments = param.addCondiments || function(){
        throw new Error( '必须传递addCondiments方法' );
    };

    var F = function(){};

    F.prototype.init = function(){
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    };

    return F;
};

var Coffee = Beverage({
    brew: function(){
        console.log( '用沸水冲泡咖啡' );
    },
    pourInCup: function(){
         console.log( '把咖啡倒进杯子' );
     },
     addCondiments: function(){
         console.log( '加糖和牛奶' );
     }
});

var Tea = Beverage({
    brew: function(){
        console.log( '用沸水浸泡茶叶' );
    },
    pourInCup: function(){
         console.log( '把茶倒进杯子' );
     },
     addCondiments: function(){
         console.log( '加柠檬' );
     }
});


var coffee = new Coffee();
coffee.init();

var tea = new Tea();
tea.init();


中介者模式

 let mediator = function() {
            let relative = {};
 
            return {
                add( name, relation ){
                    relative[name] = relation;
                },
                remove( name ) {
                    delete relative[name];
                },
                payNewYear( name ) {
                    relative[name] & console.log(`${relative[name]}, 新年好!恭喜发财红包拿来!`);
                }
            }
        }();
 
        mediator.add('狗蛋','二表舅');
        mediator.add('铁柱','五大爷');
        mediator.payNewYear('狗蛋');
        mediator.payNewYear('铁柱');
        mediator.remove('铁柱');

迭代器模式
迭代器模式是指提供一种方法顺序访问一个对象中的各个元素,又不需要暴露该对象的内部。

//内部迭代器
var each = function(arr, callback) {
    for(let i=0,l = arr.length;i < l;i++) {
        callback.call(arr[i], i, arr[i])
    }
};
each([1,2,3,4],function( i, n) {
    console.log( i, n)
})
//each 函数属于内部迭代器,函数内部已经定好了迭代规则,调用非常方便,但无法同时迭代2个数组
//外部迭代器
let iterator = function(obj) {
    let current = 0 // 
    let next = function() {
        current += 1
    }
    let isDone = function() {
        return current >= obj.length
    }
    let getcurrent = function(){
        return obj[current]
    }
    return {
        next: next,
        isDone: isDone,
        getCurrItem: getcurrent
    }
}

let compare = function(iterator1, iterator2) {
    while( !iterator1.isDone() && !iterator2.isDone()){
        if ( iterator1.getcurrent() !== iterator2.getcurrent() ){ 
            throw new Error ( 'iterator1 和 iterator2 不相等' );
        } 
        iterator1.next(); 
        iterator2.next();
    }
}
var iterator1 = Iterator( [ 1, 2, 3 ] ); 
var iterator2 = Iterator( [ 1, 2, 3 ] );
compare( iterator1, iterator2 ); // 输出:iterator1 和 iterator2 相等

//外部迭代器相对比较复杂,但是可以实现更多的需求,也能满足更多变的需求,两种迭代器没有优劣之分,按场景来判断究竟使用哪个迭代器。


组合模式

 

// 创建一个宏命令
var MacroCommand = function(){
    return {
        // 宏命令的子命令列表
        commandsList: [],
        // 添加命令到子命令列表
        add: function( command ){
            this.commandsList.push( command );
        },
        // 依次执行子命令列表里面的命令
        execute: function(){
            for ( var i = 0, command; command = this.commandsList[ i++ ]; ){
                command.execute();
            }
        }
    }
};
 
<!--打开空调命令-->
var openAcCommand = {
    execute: function(){
        console.log( '打开空调' );
    }
};
 
<!--打开电视和音响-->
var openTvCommand = {
    execute: function(){
        console.log( '打开电视' );
    }
};
var openSoundCommand = {
    execute: function(){
        console.log( '打开音响' );
    }
};
//创建一个宏命令
var macroCommand1 = MacroCommand();
//把打开电视装进这个宏命令里
macroCommand1.add(openTvCommand)
//把打开音响装进这个宏命令里
macroCommand1.add(openSoundCommand)
 
<!--关门、打开电脑和打登录QQ的命令-->
var closeDoorCommand = {
    execute: function(){
        console.log( '关门' );
    }
};
var openPcCommand = {
    execute: function(){
        console.log( '开电脑' );
    }
};
var openQQCommand = {
    execute: function(){
        console.log( '登录QQ' );
    }
};
//创建一个宏命令
var macroCommand2 = MacroCommand();
//把关门命令装进这个宏命令里
macroCommand2.add( closeDoorCommand );
//把开电脑命令装进这个宏命令里
macroCommand2.add( openPcCommand );
//把登录QQ命令装进这个宏命令里
macroCommand2.add( openQQCommand );
 
<!--把各宏命令装进一个超级命令中去-->
var macroCommand = MacroCommand();
macroCommand.add( openAcCommand );
macroCommand.add( macroCommand1 );
macroCommand.add( macroCommand2 );

状态模式

  class StoreContext{
        constructor(){
            this.state = new LowState(this);
        }
        setState(state){
            this.state = state;
        }
        getState(){
            return this.state;
        }
        //分数合计
        add(score){
            this.state.addScore(this,score);
        }
    }
    class Score{
        //抽象方法,检查当前状态
        checkState(context){}
        //分数合计-状态之间的业务逻辑
        addScore(context,score){
            console.log("当前分数:"+this.score+",当前状态:"+this.stateName);
            console.log("加上"+score+"之后,");
            this.score += score;
            this.checkState(context);
            console.log("分数为:"+this.score+",状态为:"+context.getState().stateName);
        }
    }
    class LowState extends Score{
        constructor(state){
            super(state);
            this.stateName = "不及格";
            this.score = state.score||0;
        }
        checkState(context){
            if(this.score>=90 ){
                //大于90分时,状态为【优秀】
                context.setState(new HighState(this))
            }else if(this.score>=60){
                //大于60分时,状态为【中等】
                context.setState(new MiddleState(this))
            }
        }
    }
    class MiddleState extends Score{
        constructor(state){
            super(state);
            this.stateName = "中等";
            this.score = state.score;
        }
        checkState(context){
            if(this.score<60 ){
                //小于60分时,状态为【不及格】
                context.setState(new LowState(this))
            }else if(this.score>=90){
                context.setState(new HighState(this))
            }
        }
    }
    class HighState extends Score{
        constructor(state){
            super(state);
            this.stateName = "优秀";
            this.score = state.score;
        }
        checkState(context){
            if(this.score<60 ){
                context.setState(new LowState(this))
            }else if(this.score<90){
                context.setState(new MiddleState(this))
            }
        }
    }
    class Customer{
        static main(){
            let context = new StoreContext();
            context.add(30);
            context.add(40);
            context.add(-60);
            context.add(100);
        }
    }
    Customer.main();


享元模式
享元模式的核心是运用共享技术来有效支持大量细粒度的对象。

var Model = function( sex ){
    this.sex = sex;
};
Model.prototype.takePhoto = function(){
    console.log( 'sex= ' + this.sex + ' underwear=' + this.underwear);
};
var maleModel = new Model( 'male' ),
femaleModel = new Model( 'female' );
for ( var i = 1; i <= 50; i++ ){
    maleModel.underwear = 'underwear' + i;
    maleModel.takePhoto();
};
for ( var j = 1; j <= 50; j++ ){
    femaleModel.underwear = 'underwear' + j;
    femaleModel.takePhoto();
};

备忘录模式

// 备忘类
class Memento {
    constructor(content) {
        this.content = content;
    }
 
    getContent() {
        return this.content;
    }
}
 
// 备忘列表
class CarTaker {
    constructor() {
        this.list = [];
    }
 
    add(memento) {
        this.list.push(memento);
    }
 
    get(index) {
        return this.list[index];
    }
 
    getList() {
        return this.list
    }
}
 
// 编辑器
class Editor {
    constructor() {
        this.content = null;
    }
 
    setContent(content) {
        this.content = content;
    }
 
    getContent() {
        return this.content;
    }
 
    saveContentToMemento() {
        return new Memento(this.content);
    }
 
    getConentFromMemento(memento) {
        this.content = memento.getContent();
    }
}
 
// 测试代码
let editor = new Editor()
let careTaker = new CarTaker()
 
editor.setContent('111')
editor.setContent('222')
 
careTaker.add(editor.saveContentToMemento())  // 将当前222内容备份
editor.setContent('333')
careTaker.add(editor.saveContentToMemento())  // 将当前333内容备份
editor.setContent('444')
 
console.log(editor.getContent())
editor.getConentFromMemento(careTaker.get(1)) // 撤销
console.log(editor.getContent())
editor.getConentFromMemento(careTaker.get(0)) // 撤销
console.log(editor.getContent())
var order500 = function (orderType,pay,stock) {
    if(orderType === 1 && pay === true){
        console.log("500元定金预购,得到100元优惠券");
    }else{
        return "nextSuccessor";
    }
}


var order200 = function (orderType,pay,stock) {
    if(orderType === 2 && pay === true){
        console.log("200元定金预购,得到50元优惠券");
    }else{
        return "nextSuccessor";
    }
}

var orderNormal = function (orderType,pay,stock) {
    if(stock > 0){
        console.log("普通购买无优惠券");
    }else{
        console.log("手机库存不足");
    }
}

var Chain = function (fn) {
    this.fn = fn;
    this.successor = null;
}

Chain.prototype.setSuccessor = function (fn) {
    return this.successor = fn;
}

Chain.prototype.passRequest = function () {
    var ret = this.fn.apply(this, arguments);
    if(ret === "nextSuccessor"){
        return this.successor && this.successor.passRequest.apply(this.successor,arguments);
    }
    return ret;
}

var chainOrder500 = new Chain(order500);
var chainOrder200 = new Chain(order200);
var chainOrderNormal = new Chain(orderNormal);

chainOrder500.setSuccessor(chainOrder200);
chainOrder200.setSuccessor(chainOrderNormal);

chainOrder500.passRequest(1,false,0);


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值