当前位置:   article > 正文

前端常用设计模式_前端中的设计模式 说一些场景

前端中的设计模式 说一些场景

一、单例模式

定义:保证一个类只有一个实例,并且提供一个访问它的全局访问点。
使用场景:一些对象我们往往只需要一个,比如线程池、全局缓存、浏览器中的window对象、登录浮窗等。
实现:用一个变量标识当前是否已经为某个类创建过对象,如果是,则在下一次获取这个类的实例时,直接返回之前创建的对象。
优点:可以用来划分命令空间,减少全局变量的数量。
可以被实例化,且实例化一次,再次实例化生成的也是第一个实例。

1. 例子1

//单例模式
var Singleton = function(name) {
    this.name = name
    this.instance = null
};
Singleton.prototype.getName = function() {
    return this.name;
};
// 获取实例对象
Singleton.getInstance = function(name) {
        if (!this.instance) {
            this.instance = new Singleton(name)
        }
        return this.instance
    }
    //测试单例模式的实例
var a = Singleton.getInstance('aa')
var b = Singleton.getInstance('bb')
console.log(a === b); // true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

2.例子2

(function() {
    // 管理单例的逻辑代码,如果没有数据则创建,有数据则返回
    var getSingle = function(fn) { // 参数为创建对象的方法
        var result;
        return function() { // 判断是null 或赋值
            return result || (result = fn.apply(this, arguments))
        };
    };
    // 创建登录窗口方法
    var createLoginLayer = function() {
        var div = document.createElement('div');
        div.innerHTML = '我是登录浮窗'
        div.style.display = 'none'
        document.body.appendChild(div)
        return div;
    };
    // 单例方法
    var createSingleLoginLayer = getSingle(createLoginLayer)
        // 使用惰性单例,进行创建
    document.getElementById('loginBtn').onlick = function() {
        var loginLayer = createSingleLoginLayer();
        loginLayer.style.display = 'block'
    };
})()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

二、观察者模式

定义:对象间的一种一对多的依赖关系。
使用场景:当一个对象的状态发生变化时,所有依赖于他的对象都将得到通知。
优点:时间上的解耦,对象之间的解耦。
实现:

  • 首先,指定好谁充当发布者;
  • 然后,给发布者添加一个缓存列表,用于存放回调函数以便通知订阅者;
  • 最后,发布消息时,发布者会遍历这个缓存列表,依次触发里面存放的订阅者回调函数。

1. 例子1

 var salesOffices = {}; // 定义售楼处
        salesOffices.clientList = []; // 缓存列表,存放订阅者的回调函数
        salesOffices.listen = function(fn) { // 增加订阅者
            this.clientList.push(fn) // 订阅的消息添加进缓存列表
        };
        salesOffices.trigger = function() { // 发布消息
            for (var i = 0, fn; fn = this.clientList[i++];) {
                fn.apply(this, arguments); // arguments 是发布消息时带上的参数。
            }
        };
        //调用
        salesOffices.listen(function(price, squareMeter) { // 订阅消息
            console.log('价格=' + price);
            console.log('squareMeter=' + squareMeter);
        });
        salesOffices.trigger(2000000, 88); // 输出: 200 万,88 平方米
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2. 例子2

登录页面后,需要刷新各个模块的信息(头像,nav)。

var ObserverEvent = (function() {
     var clientList = [],
         listen, trigger, remove;
     listen = function(key, fn) {
         if (!clientList[key]) {
             clientList[key] = [];
         }
         clientList[key].push(fn);
     };
     trigger = function() {
         var key = Array.prototype.shift.call(arguments),
             fns = clientList[key];
         if (!fns || fns.length === 0) {
             return false
         }
         for (var i = 0, fn; fn = fns[i++];) {
             fn.apply(this, arguments)
         }
     };
     remove = function(key, fn) {
         var fns = clientList[key];
         if (!fns) {
             return false
         }
         if (!fn) {
             fns && (fns.length = 0)
         } else {
             for (var l = fns.length - 1; l >= 0; l--) {
                 var _fn = fns[l];
                 if (_fn === fn) {
                     fns.splice(l, 1);
                 }
             }
         }
     };
     return {
         listen: listen,
         trigger: trigger,
         remove: remove
     }
 })();
 ObserverEvent.listen('squareMeter88', fn1 = function(price) {
     console.log('价格=' + price);
 });
 ObserverEvent.listen('squareMeter100', function(price) {
     console.log('价格=' + price);
 });
 ObserverEvent.trigger('squareMeter88', 200000);
 //刷新模块信息
 var header = (function() {
     ObserverEvent.listen('loginSucc', function(data) {
         header.setAvatar(data.avatar);
     });
     return {
         setAvatar: function(data) {
             console.log(data + "设置header成功");
         }
     }
 })();
 var nav = (function() {
     ObserverEvent.listen('loginSucc', function(data) {
         nav.setAvatar(data.avatar)
     });
     return {
         setAvatar: function(data) {
             console.log(data + '设置nav成功');
         }
     }
 })();
 var data = {};
 data.avatar = '参数';
 ObserverEvent.trigger('loginSucc', data)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72

三、工厂模式

定义:将其成员对象的实例化推迟到子类来实现的类。
需求:创建对象的流程赋值的时候,比如依赖很多设置文件等;处理大量具有相同属性的小对象;注意:不能滥用。
分类:简单工厂,工厂方法和抽象工厂。

(一)简单工厂模式(创建单一对象,需要的类比较少)

let UserFactory = function(role) {
    function SuperAdmin() {
        this.name = '超级管理员';
        this.viewPage = ['首页', '通讯录', '发现页', '应用数据', '权限管理']
    }

    function Admin() {
        this.name = '管理员';
        this.viewPage = ['首页', '通讯录', '发现页']
        console.log(this.name, this.viewPage);
    }

    function NormalUser() {
        this.name = '普通用户';
        this.viewPage = ['首页', '通讯录', '发现页']
    }
    switch (role) {
        case 'superAdmin':
            return new SuperAdmin();
            break;
        case 'admin':
            return new Admin();
            break;
        case 'user':
            return new NormalUser();
            break;
        default:
            throw new Error('参数错误,可选参数:superAdmin,admin,user')
    }
}

UserFactory('admin');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

(二)工厂方法模式(创建多类对象,需要的类比较多)

为方便后续新增类方便,只需改一处代码,封装了工厂方法而已。并且把类都放在工厂类原型中实现。

// 安全模式创建的工厂方法函数
 let UserFactory = function(role) {
     if (this instanceof UserFactory) {
         var s = new this[role]();
         return s;
     } else {
         return new UserFactory(role);
     }
 }

 // 工厂方法函数的原型中设置所有对象的构造函数
 UserFactory.prototype = {
     SuperAdmin: function() {
         this.name = '超级管理员'
         this.viewPage = ['首页', '通讯录', '发现页', '应用数据', '权限管理']
     },
     Admin: function() {
         this.name = '管理员';
         this.viewPage = ['首页', '通讯录', '发现页', '应用数据']
     },
     NormalUser: function() {
         this.name = '普通用户';
         this.viewPage = ['首页', '通讯录', '发现页']
     }
 }

 // 调用
 let superAdmin = UserFactory('SuperAdmin')
 let admin = UserFactory('Admin')
 let NormalUser = UserFactory('NormalUser')
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

(三)抽象工厂模式

创建父类,子类继承父类,具体实现在子类。
抽象工厂其实是实现子类继承父类的方法,只是一个方法。
抽象工厂模式一般用在多人协作的超大型项目中,并且严格的要求项目以面向对象的思想进行完成。

// 抽象工厂方法
var VehicleFactory = function(subType, superType) {
    // 判断抽象工厂中是否有该抽象类
    if (typeof VehicleFactory[superType] === 'function') {
        // 缓存类
        function F() {};
        // 继承父类属性和方法
        F.prototype = new VehicleFactory[superType]();
        // 将子类构造函数指向子类
        subType.constructor = subType
            // 子类原型继承父类
        subType.prototype = new F()
    } else {
        // 不存在该抽象类抛出错误
        throw new Error('未创建该抽象类')
    }
};

// 小汽车抽象类
VehicleFactory.Car = function() {
    this.type = 'car';
};
VehicleFactory.Car.prototype = {
    getPrice: function() {
        return new Error('抽象方法不能调用')
    },
    getSpeed: function() {
        return new Error('抽象方法不能调用')
    }
};
// 公交车抽象类
VehicleFactory.Bus = function() {
    this.type = 'bus'
};
VehicleFactory.Bus.prototype = {
    getPrice: function() {
        return new Error('抽象方法不能调用')
    },
    getSpeed: function() {
        return new Error('抽象方法不能调用')
    }
};
// 货车抽象类
VehicleFactory.Truck = function() {
    this.type = 'truck'
};
VehicleFactory.Truck.prototype = {
    getPrice: function() {
        return new Error('抽象方法不能调用');
    },
    getSpeed: function() {
        return new Error('抽象方法不能调用')
    }
};

// 使用:创建产品子类继承相应的产品组抽象类
// 宝马汽车子类
var BMW = function(price, speed) {
    this.price = price
    this.speed = speed
}

// 抽象工厂实现对Car抽象类的继承
VehicleFactory(BMW, 'Car');
BMW.prototype.getPrice = function() {
    return this.price
}
BMW.prototype.getSpeed = function() {
    return this.speed
}

// 公交车...
// 货车...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

四、命令模式

定义: 用来对方法调用进行参数化处理和传送,经过这样处理过的方法调用可以在任何需要的时候进行执行。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/556139
推荐阅读
相关标签
  

闽ICP备14008679号