序列文章
JS 面试之函数 (1)JS 面试之对象 (2)JS 面试之数组的几个不 low 操作 (3)JS 面试之 http0.9~3.0 对比分析 (4)JS 面试之数据结构与算法 (5)
前言
设计模式如果应用到项目中,可以实现代码的复用和解耦,提高代码质量。本文主要介绍 14 种设计模式写 UI 组件, 封装框架必备
1. 简单工厂模式
1. 定义:又叫静态工厂方法,就是创建对象,并赋予属性和方法 2. 应用:抽取类相同的属性和方法封装到对象上 3. 代码:
let UserFactory = function (role) {
function User(opt) {
this.name = opt.name;
this.viewPage = opt.viewPage;
}
switch (role) {
case ‘superAdmin’:
return new User(superAdmin);
break;
case ‘admin’:
return new User(admin);
break;
case ‘user’:
return new User(user);
break;
default:
throw new Error(‘ 参数错误, 可选参数:superAdmin、admin、user’)
}
}
// 调用
let superAdmin = UserFactory(‘superAdmin’);
let admin = UserFactory(‘admin’)
let normalUser = UserFactory(‘user’)
// 最后得到角色, 可以调用
2. 工厂方法模式
1. 定义:对产品类的抽象使其创建业务主要负责用于创建多类产品的实例 2. 应用: 创建实例 3. 代码:
var Factory=function(type,content){
if(this instanceof Factory){
var s=new this[type](content);
return s;
}else{
return new Factory(type,content);
}
}
// 工厂原型中设置创建类型数据对象的属性
Factory.prototype={
Java:function(content){
console.log(‘Java 值为 ’,content);
},
PHP:function(content){
console.log(‘PHP 值为 ’,content);
},
Python:function(content){
console.log(‘Python 值为 ’,content);
},
}
// 测试用例
Factory(‘Python’,’ 我是 Python’);
3. 原型模式
1. 定义: 设置函数的原型属性 2. 应用: 实现继承 3. 代码:
function Animal (name) {
// 属性
this.name = name || ‘Animal’;
// 实例方法
this.sleep = function(){
console.log(this.name + ‘ 正在睡觉!’);
}
}
// 原型方法
Animal.prototype.eat = function(food) {
console.log(this.name + ‘ 正在吃:’ + food);
};
function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = ‘cat’;
// Test Code
var cat = new Cat();
console.log(cat.name);//cat
console.log(cat.eat(‘fish’));//cat 正在吃:fish undefined
console.log(cat.sleep());//cat 正在睡觉!undefined
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
4. 单例模式
1. 定义: 只允许被实例化依次的类 2. 应用: 提供一个命名空间 3. 代码:
let singleCase = function(name){
this.name = name;
};
singleCase.prototype.getName = function(){
return this.name;
}
// 获取实例对象
let getInstance = (function() {
var instance = null;
return function(name) {
if(!instance) {// 相当于一个一次性阀门, 只能实例化一次
instance = new singleCase(name);
}
return instance;
}
})();
// 测试单体模式的实例, 所以 one===two
let one = getInstance(“one”);
let two = getInstance(“two”);
5. 外观模式
1. 定义: 为子系统中的一组接口提供一个一致的界面 2. 应用: 简化复杂接口 3. 代码: 外观模式
6. 适配器模式
1. 定义: 将一个接口转换成客户端需要的接口而不需要去修改客户端代码,使得不兼容的代码可以一起工作 2. 应用: 适配函数参数 3. 代码: 适配器模式
7. 装饰者模式
1. 定义: 不改变原对象的基础上, 给对象添加属性或方法 2. 代码
let decorator=function(input,fn){
// 获取事件源
let input=document.getElementById(input);
// 若事件源已经绑定事件
if(typeof input.onclick==’function’){
// 缓存事件源原有的回调函数
let oldClickFn=input.onclick;
// 为事件源定义新事件
input.onclick=function(){
// 事件源原有回调函数
oldClickFn();
// 执行事件源新增回调函数
fn();
}
}else{
// 未绑定绑定
input.onclick=fn;
}
}
// 测试用例
decorator(‘textInp’,function(){
console.log(‘ 文本框执行啦 ’);
})
decorator(‘btn’,function(){
console.log(‘ 按钮执行啦 ’);
})
8. 桥接模式
1. 定义: 将抽象部分与它的实现部分分离,使它们都可以独立地变化 2. 代码桥接模式
9. 模块方法模式
1. 定义: 定义一个模板, 供以后传不同参数调用 2. 代码: 模块方法模式
10. 观察者模式
1. 作用: 解决类与对象, 对象与对象之间的耦合 2. 代码:
let Observer=
(function(){
let _message={};
return {
// 注册接口,
//1. 作用: 将订阅者注册的消息推入到消息队列
//2. 参数: 所以要传两个参数, 消息类型和处理动作,
//3. 消息不存在重新创建, 存在将消息推入到执行方法
regist:function(type,fn){
// 如果消息不存在, 创建
if(typeof _message[type]===’undefined’){
_message[type]=[fn];
}else{
// 将消息推入到消息的执行动作
_message[type].push(fn);
}
},
// 发布信息接口
//1. 作用: 观察这发布消息将所有订阅的消息一次执行
//2. 参数: 消息类型和动作执行传递参数
//3. 消息类型参数必须校验
fire:function(type,args){
// 如果消息没有注册, 则返回
if(!_message[type]) return;
// 定义消息信息
var events={
type:type, // 消息类型
args:args||{} // 消息携带数据
},
i=0,
len=_message[type].length;
// 遍历消息
for(;i<len;i++){
// 依次执行注册消息
_message[type][i].call(this,events);
}
},
// 移除信息接口
//1. 作用: 将订阅者注销消息从消息队列清除
//2. 参数: 消息类型和执行的动作
//3. 消息参数校验
remove:function(type,fn){
// 如果消息动作队列存在
if(_message[type] instanceof Array){
// 从最后一个消息动作序遍历
var i=_message[type].length-1;
for(;i>=0;i–){
// 如果存在该动作在消息队列中移除
_message[type][i]===fn&&_message[type].splice(i,1);
}
}
}
}
})()
// 测试用例
//1. 订阅消息
Observer.regist(‘test’,function(e){
console.log(e.type,e.args.msg);
})
//2. 发布消息
Observer.fire(‘test’,{msg:’ 传递参数 1 ′});
Observer.fire(‘test’,{msg:’ 传递参数 2 ′});
Observer.fire(‘test’,{msg:’ 传递参数 3 ′});
11. 状态模式
1. 定义: 一个对象状态改变会导致行为变化 2. 作用: 解决复杂的 if 判断 3. 代码状态模式
12. 策略模式
1. 定义: 定义了一系列家族算法,并对每一种算法单独封装起来,让算法之间可以相互替换,独立于使用算法的客户 2. 代码策略模式
13. 访问模式
1. 定义: 通过继承封装一些该数据类型不具备的属性,2. 作用: 让对象具备数组的操作方法 3. 代码: 访问者模式
14. 中介者模式
1. 定义: 设置一个中间层, 处理对象之间的交互 2. 代码: 中介者模式