20191220-汪刚强-javaScript设计模式

问题1: 什么是设计模式?

答: 每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复的劳动。

问题2: 设计模式的四个基本要素是什么?

答: 模式名,一个助记词,它用一两次来描述模式的问题,解决方案和效果。
问题, 描述了应该在何时使用模式。它解释了设计问题和问题存在的前因后果。
解决方案, 描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。
效果, 描述了模式应用的效果及使用模式需要权衡的问题。

结构性设计模式

问题3: 套餐服务------外观模式

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

// 场景: document.onclick = function(){} 有弊端
// onclick是DOM0级事件,也就是说这种方式绑定的事件相当于为元素绑定一个事件方法,其他人在绑定这个方法就被覆盖了
// 解决方法就是使用DOM2级事件处理程序,addEventListener(低于Ie9不支持),attachEvent,如果浏览器不支持DOM2就只能用onclick了
// 这里可以使用外观模式进行兼容处理

import React, { Component }  from 'react';

class appearanceMode extends Component {
    componentDidMount() {
       let dom =  document.getElementById("demo");
        this.addEvent(dom, 'click', function() {
            console.log("这里执行了点击");
        })
    }
    addEvent = (dom:any, type:string, fn: any)=>{
        // 对于支持DOM2级事件处理程序addEventListener方法的浏览器
        if(dom.addEventListener) {
            console.log(1);
            dom.addEventListener(type, fn, false);
        }else if(dom.attachEvent) {
            // 对于支持不支持addEventListener,但支持attachEvent方法的浏览器
            console.log(2);
            dom.attachEvent('on'+type, fn);
        }else {
            // 对于支持不支持addEventListener,也不支持attachEvent, 但支持 on+'事件名'的浏览器
            console.log(3);
            dom['on'+type] = fn;
        }
    }
    render() {
      return (
        <div id="demo">
           点击我来测试外观模式
        </div>
      );
    }
  }
 export default appearanceMode

行为型设计模式

问题4:观察者模式:又称发布订阅者模式或消息机制,定义了一种依赖关系,解决了主题与观察者之间功能的耦合。当一个对象被修改时,则会自动通知它的依赖对象

import { type } from "os";
import Test from "../../components/assets/uploadImg/uoloadFiles";


//在数组中,函数使用JSON.string会转换成null
//undefined、任意的函数以及 symbol 值,在序列化过程中会被忽略(出现在非数组对象的属性值中时)或者被转换成 null(出现在数组中时)
//使用json.string的第二个参数将函数转换成string类型
function toStringFn(key, value){
    if(typeof value == 'function') {
        value = ''+value;
    }
    return value;
}


//将观察者放在闭包中,当页面加载就立即执行
var Observer = (function() {
    //防止信息队列暴露而被篡改故将消息容器作为静态私有变量保存
    //只有remove接口才可以移除调订阅

    var _messages = JSON.parse(sessionStorage.getItem('_messages')) || {};
   
    console.log(_messages);
    return {
        //注册消息接口
        register: function(type, fn) {
            //如果此消息不存在则应该创建一个该消息类型
            if(typeof _messages[type] === 'undefined') {
                //将动作推入到该消息对应的动作执行队列中
                _messages[type] = [fn];
            }else{
                //如果此消息存在
                //将动作方法推入该消息对应的动作执行序列中

                //已经存在的动作执行不重复添加
                if(!_messages[type].includes(""+fn)) {
                    _messages[type].push(fn);
                }
            }
            sessionStorage.setItem('_messages', JSON.stringify(_messages, toStringFn));
        },

        //发布消息接口
        fire: function(type, args) {
            //如果该消息没有被注册则返回
            if(!_messages[type])
                return;
            
            //定义消息信息
            var events = {
                type: type,
                args: args || []
            },

            i = 0,
            len = _messages[type].length;
            //遍历消息动作
            for(; i < len; i++){
                //依次执行注册的消息对应的动作序列
            //    let test = new Function(_messages[type][i]);
                console.log(_messages[type][i]);

                
                eval("return"+_messages[type][i]).call(this, events);
                console.log("111",typeof test);
                _messages[type][i].call(this, events);
            }   
        },

        //移除接口
        remove: function(type, fn) {
            //如果消息动作队列存在
            if(_messages[type] instanceof Array){
                //从最后一个消息动作遍历
                var i = _messages[type].length - 1;
                for(; i >= 0; i--){
                    //如果存在该动作则在消息动作序列中移除相应动作
                    _messages[type][i] === fn && _messages[type].splice(i, 1);
                }
                sessionStorage.setItem('_messages', JSON.stringify(_messages, toStringFn));
            }
        }
    }
})()

export default Observer;

问题5: 策略模式: 定义系列的算法,把它们一个个封装起来, 并且使它们可相互替换,在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。

问题6: 神奇的魔法师——————简单工厂模式

答: 简单工厂模式: 又叫静态工厂方法,由一个工厂对象决定创建某一种产品对象类的实例


// 场景: 比如体育商品店买体育器材,里面有很多体育用品,以其相关介绍等
// 当你来到体育用品店买一个篮球及其相关介绍时,你只需要问售货员,他会帮你找到想要的东西
// 售后员相当于工厂函数,这个函数可以创建你想要的对象,你不必去关心是如何创建的,这个售货员很多人都可以问他,体现其可复用性
// 这个工厂模式很像一个魔法师,你想要魔法师给你变礼物,不过你不需要知道魔法师是用什么变的,你只需要找这个魔法师就行了


// 举一反三:警告框,确认框,提示框

import React, { Component }  from 'react';

// 篮球基类
class Basketbll {
  intro: string;  // 定义类的属性
  constructor() {
    this.intro = "篮球盛行于美国"
  };

  // 定义类的方法
  getMember() {
    console.log("每个队伍需要5名队员");
  };
  getBallSize() {
    console.log("这个是7号篮球");
  }
}


// 足球基类
class Football {
  intro: string; // 定义类的属性
  constructor() {
    this.intro = "足球在世界范围内流行"
  };

  // 定义类的方法
  getMember() {
    console.log("每个队伍需要11名队员");
  };
  getBallSize() {
    console.log("这个足球很大");
  }
}

// 网球基类
class Tennis{
  intro: string; // 定义类的属性
  constructor() {
    this.intro = "每年有很多网球系列赛";
  };

  // 定义类的方法
  getMember(){
    console.log("每个队伍需要1名队员");
  };
  getBallSize(){
    console.log("网球很小");
  }
}


// 运动工厂,魔法师,它能帮我们实例化出许多对象,  这样其他使用的人只需要知道运动工厂就行了,对于内部的实现并不关心
let SportsFactory = (name: string) => {
  switch(name){
    case 'NBA':
      return new Basketbll();
    case 'wordCup':
      return new Football();
    case 'tennis':
      return new Tennis
    default: 
      return new Basketbll();
  }
}


class simpleFactoryMode extends Component {
  wantToBuy = (keyWord: string) => {
    let goods = SportsFactory(keyWord);
    goods.getMember();
    goods.getBallSize();
  }
  render() {
    return (
      <div >
        <div onClick={()=>this.wantToBuy("NBA")}>我要买篮球</div>
        <div onClick={()=>this.wantToBuy("wordCup")}>我要买足球</div>
        <div onClick={()=>this.wantToBuy("tennis")}>我要买网球</div>
      </div>
    );
  }
}

export default simpleFactoryMode


问题7:给我一张名片------工厂方法模式

答:工厂方法模式:通过对产品类的抽象使其创建业务主要负责用于创建多类产品的实例


// 场景:如何处理需求不断在变化的业务,如:投放广告。
// 思考:比起使用简单工厂模式用哪些好处

import React, { Component }  from 'react';
import { red } from 'ansi-colors';

// 工厂类
class Factory {
    type: string;
    content: string;
    constructor(type: string, content: string) {
        this.type = type;
        this.content = content

    }
    java() {
        return <div style={{color: "red"}}>{this.content}</div>
    }

    php() {
        return <div style={{color: "yellow"}}>{this.content}</div>
    }

    javaScript() {
        return <div style={{color: "green"}}>{this.content}</div>
    }
    ui() {
        return <div style={{color: "blue"}}>{this.content}</div>
    }
    test() {
        return <div style={{color: "blue"}}>{this.content}</div>
    }
}

let data = [
    {type:'javaScript', content: "JavaScript哪家强"},
    {type:'java', content: "java哪家强"},
    {type:'php', content: "php哪家强"},
    {type:'javaScript', content: "JavaScript哪家强"},
    {type:'ui', content: "ui哪家强"},
    {type:'test', content: "test哪家强"},
]

class factoryMethodMode extends Component {
  
  render() {
    return (
      <div>
          {
            data.map((itemContent,index)=>(
                <div key={index}>
                    {
                        (new Factory(itemContent.type, itemContent.content) as any)[itemContent.type]()
                    }
                </div>
            ))
          }
      </div>
    );
  }
}

export default factoryMethodMode


问题8:分即是合------建造者模式

答:将一个复杂对象的构建层与其表现层相互分离,同样的构造过程可采用不同的表示


// 场景: 将应聘者简历向外推销,展示兴趣爱好,特长等,其他信息如联系方式不展示(让需求公司跟我们联系,我们再联系应聘者)
// 工厂模式主要是为了创建对象实例,关心的是最终产出的是什么,并不关心你创建的过程,建造者模式虽然其目的也是创建对象,但是其
// 更多的关心的是创建的工程,如:应聘者实例,创建工程中需要注意应聘者有哪些兴趣爱好,姓名等信息,期望岗位等等。
import React, { Component }  from 'react';
import { string, any } from 'prop-types';

// 创建一位人类
class Human {
    // 技能
    skill: string;
    // 兴趣
    hobby: string;
    name: Named;
    work: Work;
    constructor(skill:string, hobby:string){
        this.skill = skill || '保密';
        this.hobby = hobby || '保密';
        this.name = new Named("wang gang qiang");
        this.work = new Work("code");
    }
    getSkill() {
        console.log(this.skill);
    }
    getHobby() {
        console.log(this.hobby);
    }
}

// 实例化姓名类
class Named {
    wholeName: string;
    firstName: string;
    secondName: string;
    constructor(name: string) {
        this.wholeName = name;
        this.firstName = name.slice(0, name.indexOf(" "));
        this.secondName = name.slice(name.indexOf(" "));
    }
    getFirstName() {
        console.log(this.firstName);
    }
    getSecondName() {
        console.log(this.secondName);
    }
}

// 职位实例化
class  Work {
    work: string;
    workDescript: string;
    constructor(work: string) {
        // 构造函数中通过传入的职位特征来设置相应职位以及描述
        switch(work){
            case 'code':
                this.work = "工程师";
                this.workDescript = "每天沉迷于编程";
                break;
            case 'UI':
                this.work = "设计师";
                this.workDescript = "设计更似一种艺术";
                break;
            case "teach":
                this.work = "教师";
                this.workDescript = "分享也是一种快乐";
                break;
            default:
                this.work = "未知";
                this.workDescript = "对不起,我们还不清楚您所选择职位的相关描述"

        }
    }
    changeWork() {
        console.log(this.work);
    }
    changeDescript() {
        console.log(this.workDescript);
    }
}

// 应聘者建造者  name 姓名 全名  work 期望职位




class factoryMethodMode extends Component {
  
  render() {
    let person = new Human("精通Java", "xiao ming");
    console.log(person.getSkill(), person.getHobby(), person.name.getFirstName(), person.name.getSecondName(),person.work.changeDescript(), person.work.changeWork())
    return (
      <div>
          测试构造者模式
      </div>
    );
  }
}

export default factoryMethodMode


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。