梳理前端的设计模式

115 阅读3分钟

一、单例模式

单例模式 (Singleton Pattern)又称为单体模式,保证一个类只有一个实例,并提供一个访问它的全局访问点。也就是说,第二次使用同一个类创建新对象的时候,应该得到与第一次创建的对象完全相同的对象。

举例:vuex,全局只有一个store

二、工厂模式

工厂模式就是根据不用的输入返回不同的实例,一般用来创建同一类对象,它的主要思想就是将对象的创建与对象的实现分离。

举例:vue-router 中使用了工厂模式的思想来获得相应路由控制类的实例。

export default class VueRouter {  
    constructor(options) {  
        this.mode = mode    // 路由模式  
          
        switch (mode) {           // 简单工厂  
            case 'history':       // history 方式  
                this.history = new HTML5History(this, options.base)  
                break  
            case 'hash':          // hash 方式  
                this.history = new HashHistory(this, options.basethis.fallback)  
                break  
            case 'abstract':      // abstract 方式  
                this.history = new AbstractHistory(this, options.base)  
                break  
            default:  
                // ... 初始化失败报错  
        }  
    }  
}

三、策略模式

策略模式 (Strategy Pattern)又称政策模式,其定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。封装的策略算法一般是独立的,策略模式根据输入来调整采用哪个算法。关键是策略的实现和使用分离。

举例:表格 formatter,不同场景;策略不同

首先实现文件计算的算法:


export const StrategyMap = {  
    // Strategy 1: 将文件大小(bit)转化为 KB   
    bitToKBval => {  
        const num = Number(val)  
        return isNaN(num) ? val : (num / 1024).toFixed(0) + 'KB'  
    },  
    // Strategy 2: 将文件大小(bit)转化为 MB   
    bitToMBval => {  
        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){  
      StrategyMap[type](row[rowKey])  
  }  
}  
export default strategyContext

在组件中直接使用:

<template>  
    <el-table :data="tableData">  
        <el-table-column prop="date" label="日期"></el-table-column>  
        <el-table-column prop="name" label="文件名"></el-table-column>  
        <!-- 直接调用 strategyContext -->  
        <el-table-column prop="sizeKb" label="文件大小(KB)"  
                         :formatter='strategyContext("bitToKB", "sizeKb")'>  
        </el-table-column>  
        <el-table-column prop="sizeMb" label="附件大小(MB)"  
                         :formatter='strategyContext("bitToMB", "sizeMb")'>  
        </el-table-column>  
    </el-table>  
</template>  
<script type='text/javascript'>  
    import strategyContext from './strategyContext.js'  
      
    export default {  
        name'ElTableDemo',  
        data() {  
            return {  
                strategyContext,  
                tableData: [  
                    { date'2019-05-02'name'文件1'sizeKb1234sizeMb1234426 },  
                    { date'2019-05-04'name'文件2'sizeKb4213sizeMb8636152 }]  
            }  
        }  
    }  
</script>

四、代理模式

代理模式 (Proxy Pattern)又称委托模式,它为目标对象创造了一个代理对象,以控制对目标对象的访问。

举例:axios拦截器、vue的源码Object.defineProperty

在项目中经常使用 Axios 的实例来进行 HTTP 的请求,使用拦截器 interceptor 可以提前对 request 请求和 response 返回进行一些预处理

五、适配器模式

适配器模式(Adapter Pattern)又称包装器模式,将一个类(对象)的接口(方法、属性)转化为用户需要的另一个接口,解决类(对象)之间接口不兼容的问题。

举例:Vue 中的计算属性也是一个适配器模式的实例,以官网的例子为例

<template>  
    <div id="example">  
        <p>Original message: "{{ message }}"</p>  <!-- Hello -->  
        <p>Computed reversed message: "{{ reversedMessage }}"</p>  <!-- olleH -->  
    </div>  
</template>  
<script type='text/javascript'>  
    export default {  
        name'demo',  
        data() {  
            return {  
                message'Hello'  
            }  
        },  
        computed: {  
            reversedMessagefunction() {  
                return this.message.split('').reverse().join('')  
            }  
        }  
    }  
</script>

对原有数据并没有改变,只改变了原有数据的表现形式。

六、观察者模式/发布订阅模式

发布-订阅模式是观察者模式的一个别名,但两者又有所不同。 image.png


// 发布订阅模式
class PubSub { 
   constructor() { 
      this.subscribers = {}; 
   } 
   subscribe(event, callback) {
     if (!this.subscribers[event]) { 
       this.subscribers[event] = []; 
     } 
     this.subscribers[event].push(callback); 
   }
   publish(event, data) { 
     if (!this.subscribers[event]) {
       return;
     }
     this.subscribers[event].forEach(callback => { 
       callback(data);
     }); 
   } 
 }
 // 创建一个发布订阅对象 
 const pubSub = new PubSub(); 
 // 订阅事件 
 pubSub.subscribe('event1', data => { 
   console.log('订阅event1的回调函数执行了,data为:',   data);
 }); 
 // 发布事件 
 pubSub.publish('event1', 'hello world');

转载自:www.cnblogs.com/cczlovexw/p…