• 适合用设计模式解决的问题场景


    在曾探的《Javascript设计模式与开发实践》中,有这样一段话:

    设计模式在很多时候其实都体现了语言的不足之处。Peter Norvig 曾说,设计模式是对语言不足的补充,如果使用设计模式,不如去找一门更好的语言。这句话非常正确。

    而在我看来,语言未必要封装设计模式,设计模式也不必须封装在语言内部。设计模式并不完全是语言不足的补充,而是一种不分语言针对特定问题的通用性解决方案。

    我在研究生阶段曾经研究过过去五年的统考数学试卷。得出的结论是试卷的考题分布是有规律的。数学一共21道题(现在不知道了),分别来自高数、概率论和数理统计。

    通过分析过去五年试卷:国家教育部考试司仁慈,每个位置的题目,大概来自那本书其实也是明确的,三科分别可能出现的题目个数也是确定的。

    然后就是一定量的题海战术,研究试卷里面出现的考试题目,研究考试题目的变种。我把多个变种题目分析之后,得出一道母题,母题是相对的,表征这是一类题目。一类题目也就有相似的解决方案。

    言归正传,回到设计模式,我认为需要设计模式解决的开发场景一定是具有代表性的,是有一定难度的。而开发这件事总体有难度的场景其实是有限的,因为对于有边界的事情我认为都是有限的,业务开发肯定是有限的。

    因为有限,总结其中代表性的,常见的问题场景就很必要。搞懂这些之后,可以更加专注于开发的难点或者核心点。

    当然常见的问题场景未必需要设计模式解决。但这回只说需要用设计模式解决的场景。

    1. 全局只需要一个这样的东西,比如全局只有一个window,全局缓存对象,登录页面的登录窗口……
    • 这个时候用单例模式解决,单例模式的通用模式
    var getSingle = function( fn ){ 
        var result; 
        return function(){ 
           return result || ( result = fn .apply(this, arguments ) ); 
        } 
    }; var getSingle = function( fn ){ 
        var result; 
        return function(){ 
           return result || ( result = fn .apply(this, arguments ) ); 
        } 
    }; 

    2,多个if else怎么重构?简单的用策略模式

     
    // 原来
          function ifbox(type){
            if(type === 'a'){
              return 1
            }
            if(type === 'b'){
              return 2
            }
            if(type === 'c'){
              return 3
            }
          }
          //
          function ifbox(type){
            var obj = {
              a: 1,
              b: 2,
              c: 3
            }
            return obj[type]
          }

    复杂的用迭代器模式

     
     // 原来
          function ifbox2(){
            // type, num 为全局变量
            if(type === 'a' && num === 10){
              return 1
            }
            if(type === 'b' && num === 11){
              return 2
            }
            if(type === 'c' && num === 12){
              return 3
            }
          }
          //
          function ifbox2(){
            var ten = function (){
              if(type === 'a' && num === 10){
                 return 1
              } 
            }
            var eleven = function (){
              if(type === 'a' && num === 11){
                 return 1
              } 
            }
            var twelve = function (){
              if(type === 'a' && num === 12){
                 return 1
              } 
            }
    
            return [ten, eleven, twelve]
          }
          // 使用
          const arr = ifbox2()
          const len = arr.length
          for (let i = 0; i < len; i++) {
            if (arr[i]()) {
              return arr[i]()
            }
          }

    3,图片懒加载以及接口缓存?

    • 用代理模式,出于各种原因当一个对象不方便直接访问另一个对象时候,找个中间人来操作达到某个目的,举一个缓存代理
    先创建一个用于求乘积的函数: 
    var mult = function(){ 
     console.log( '开始计算乘积' ); 
     var a = 1; 
     for ( var i = 0, l = arguments.length; i < l; i++ ){ 
     a = a * arguments[i]; 
     } 
     return a; 
    }; 
    mult( 2, 3 ); // 输出:6 
    mult( 2, 3, 4 ); // 输出:24 
    现在加入缓存代理函数:
    var proxyMult = (function(){ 
     var cache = {}; 
     return function(){ 
     var args = Array.prototype.join.call( arguments, ',' ); 
     if ( args in cache ){ 
     return cache[ args ]; 
     } 
     return cache[ args ] = mult.apply( this, arguments ); 
     } 
    })(); 
     proxyMult( 1, 2, 3, 4 ); // 输出:24 
     proxyMult( 1, 2, 3, 4 ); // 输出:24

    4,当功能代码的使用者和开发者不是一个人时候

    • 用观察者模式或者发布订阅模式
    var salesOffices = {}; // 定义售楼处
    salesOffices.clientList = {}; // 缓存列表,存放订阅者的回调函数
    salesOffices.listen = function( key, fn ){ 
     if ( !this.clientList[ key ] ){ // 如果还没有订阅过此类消息,给该类消息创建一个缓存列表
     this.clientList[ key ] = []; 
     } 
     this.clientList[ key ].push( fn ); // 订阅的消息添加进消息缓存列表
    }; 
    salesOffices.trigger = function(){ // 发布消息
     var key = Array.prototype.shift.call( arguments ), // 取出消息类型
     fns = this.clientList[ key ]; // 取出该消息对应的回调函数集合
     if ( !fns || fns.length === 0 ){ // 如果没有订阅该消息,则返回
     return false; 
     } 
     for( var i = 0, fn; fn = fns[ i++ ]; ){ 
     fn.apply( this, arguments ); // (2) // arguments 是发布消息时附送的参数
     } 
    }; 
    salesOffices.listen( 'squareMeter88', function( price ){ // 小明订阅 88 平方米房子的消息
     console.log( '价格= ' + price ); // 输出:2000000 
    }); 
    salesOffices.listen( 'squareMeter110', function( price ){ // 小红订阅 110 平方米房子的消息
     console.log( '价格= ' + price ); // 输出:3000000 
    }); 
    salesOffices.trigger( 'squareMeter88', 2000000 ); // 发布 88 平方米房子的价格
    salesOffices.trigger( 'squareMeter110', 3000000 ); // 发布 110 平方米房子的价格

    先总结这几个。后面两个例子代码直接使用了书中的。

    我站在山顶看风景!下面是我的家乡!
  • 相关阅读:
    JVM学习笔记之认识JDK(一)
    C#发送邮件异常:根据验证过程,远程证书无效
    windows下使用mysql双机热备功能
    批处理实现mysql的备份
    WebApi FormData+文件长传 异步+同步实现
    Oracle中已知字段名查询所在的表名
    mstsc遇到CredSSP加密Oracle修正
    使用subgit进行svn迁移至git(branch,tags)
    使用guava进行对字符串的加锁
    使用spring-data-solr做solr客户端
  • 原文地址:https://www.cnblogs.com/zhensg123/p/14669693.html
Copyright © 2020-2023  润新知