前端常用设计模式

设计模式

1. 设计模式分类

        工厂方法模式1、抽象工厂模式2、单例模式3、建造者模式4、原型模式5
        适配器模式6、装饰器模式7、代理模式8、外观模式9、桥接模式10、组合模式11、享元模式12
        策略模式13、模板方法模式14、观察者模式15、迭代子模式16、责任链模式17、命令模式18、备忘录模式19、状态模式20、访问者模式21、中介模式22、解释器模式23

2. 常用设计模式

2.1 测试页面

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>设计模式</title>
  <style>
    #div1{
      width: 100px;
      height: 100px;
      background: red;
    }
  </style>
</head>
<body>
	<!-- 用于测试单例设计模式 -->
    <button id="print">打印日志</button><br>
    <!-- 用于测试策略设计模式 -->
    <input type="text" name="" id="input"><button id="btn">注册</button><br>
    <!-- 用于测试观察者模式(发布订阅模式) -->
    <div id="div1"></div>
    <!-- 用于测试组合设计模式  -->
    <ul id="divUl"></ul>
    <!-- 用于测试备忘录设计模式  -->
    <div>
      <p id="tips" style="margin: 0;">*</p>
      <input type="text" id="originator"><button id="save">保存</button><button id="back">返回上一步</button>
    </div>
</body>
</html>

2.2 单例模式

2.2.1 作用

确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。

2.2.2 代码展示
  // 单例模式
  function Foodl(){
    // _instance 自定义属性
    if (!Foodl._instance) {
      Foodl._instance = {
        name: '单例模式'
      }
    }
    return Foodl._instance
  }

  var obj1 = new Foodl()
  var obj2 = new Foodl()

  console.log(obj1 == obj2); // true
2.2.3 案列:打印日志
  function FoodlReg(){
    if (!FoodlReg._instance) {
      FoodlReg._instance = {
        logs: [],
        print: function(){ // 输出
          var _this = this;
          var timer = setInterval(function(){
            var log = _this.logs.shift();
            if (log) {
              console.log(log);
            }else{
              clearInterval(timer)
            }
          },500)
        },
        add: function(log){ // 添加
          this.logs.push(log)
        }
      }
    }
    return FoodlReg._instance;
  }

  var arr = ["单例模式打印第一个日志","单例模式打印第二个日志","单例模式打印第三个日志","单例模式打印第四个日志"];
  for (let i = 0; i < arr.length; i++) {
    var obj = new FoodlReg()
    obj.add(arr[i])
  }

  document.getElementById("print").onclick = function(){
    var obj = new FoodlReg()
    obj.print()
  }

2.3 工厂模式

2.3.1 简单工厂模式
2.3.1.1 作用

提供一个创建一系列相关对象的入口,统一了解对象的创建职责,创建对象时无需关心具体类。

2.3.1.2 代码展示
  // 工厂模式
  function FooFactory(){
    this.name = "FooFactory"
  }
  function BarFactory(){
    this.name = "BarFactory"
  }
  // 2.1 简单工厂模式
  function FactorySimple(arg){
    var result;
    if (arg == 'foo') {
      return result = new FooFactory()
    }else if (arg == 'bar') {
      return result = new BarFactory()
    }
  }
  var obj = FactorySimple('bar')
  console.log('简单工厂模式',obj.name); // BarFactory
2.3.2 工厂模式
2.3.2.1 作用

提供一个创建一系列相关对象的入口,统一了解对象的创建职责,创建对象时无需关心具体类。
区别:使用一个工厂类进行创建。

2.3.2.2 代码展示
  // 工厂模式
  function FooFactory(){
    this.name = "FooFactory"
  }
  function BarFactory(){
    this.name = "BarFactory"
  }
    function Factory(){}

  Factory.prototype.create = function(arg){
    var result;
    if (arg == 'foo') {
      return result = new FooFactory()
    }else if (arg == 'bar') {
      return result = new BarFactory()
    }
  }

  var fact = new Factory();
  var objFact = fact.create('foo');
  console.log('工厂模式',objFact.name); // FooFactory
2.3.2.3 案列:实现ajax请求
  function Get(url){}
  Get.prototype.done = function(fn){
    var xhr = new XMLHttpRequest();
    xhr.open('GET');
    xhr.onload = function(){
      fn(xhr.responseText)
    }
  }

  function Post(url){}
  Post.prototype.done = function(fn){
    var xhr = new XMLHttpRequest();
    xhr.open('POST');
    xhr.onload = function(){
      fn(xhr.responseText)
    }
  }

  function Jsonp(url){}
  Post.prototype.done = function(fn){
    var script = document.createElement('script');
    var name = url.match(/callback=([^&]+)/)[1];
    script.src = url;
    document.body.appendChild(script);
    window[name] = fn;
  }

  function ajax(url,method){
    var result;
    switch(method){
      case 'get':
        result = new Get(url);
      break;
      case 'post':
        result = new Post(url);
      break;
      case 'jsonp':
        result = new Jsonp(url);
      break;
    }
    return result;
  }
  // 简易写法,用于明白工厂模式的原理
  // var xhr = ajax('data.php','get');
  // xhr.done(function(data){
  //   console.log(data);
  // })

  // var xhr = ajax('data.php?callback=hello','jsonp');
  // xhr.done(function(data){
  //   console.log(data);
  // })

2.4 外观模式(门面模式)

2.4.1 作用

定义了一个高层接口,把子类集合在一起,然后方便使用

2.4.2 代码展示
  // 3.外观模式
  function Search(){} // 搜索
  // 把子类集合在一起,统一管理使用
  Search.prototype.show = function(str){
    this.removeOldData() // 移除旧数据
    this.showNewData() // 展示新数据
    this.upDataPage() // 处理分页数据
  }
  Search.prototype.removeOldData = function(){}
  Search.prototype.showNewData = function(){}
  Search.prototype.upDataPage = function(){}

  var s = new Search()
  s.show('苹果')

2.5 适配器模式

2.5.1 作用

将一个类的接口转换成客户希望的另一个接口,是的原本由于接口不兼容而不能一起工作的哪些类可以一起工作

2.5.2 代码展示
  function Adapter(class1,method){
    return class1.prototype[method]
  }

  function FooTwo(){
    this.show = Adapter(FooThree,'show')
  }
  FooTwo.prototype.show = function(){
    console.log("两项插头");
  }
  function FooThree(){}
  FooThree.prototype.show = function(){
    console.log("三项插头");
  }
  var objTwo = new FooTwo()
  objTwo.show(); // 三项插头
2.5.3 案例:根据浏览器窗口大小展示不同数据
  function showPage(){
    var screen = window.innerWidth < 800 ? 'small' : 'larger';
    if (screen == 'small') {
      this.show = Adapter(showSmallPage,'show')
    }
  }
  showPage.prototype.show = function(){
    console.log("正常显示");
  }
  function showSmallPage(){}
  showSmallPage.prototype.show = function(){
    console.log("小屏幕显示");
  }

  window.onresize = function(){
    var objPage = new showPage()
    objPage.show()
  }

2.6 策略模式

2.6.1 作用

把操作封装成一个个的策略,根据不同的类型映射到不同的策略

2.6.2 代码展示
  function Tactful(){}
  Tactful.prototype.show = function(obj){
    obj.print()
  }
  function FooTactful(){}
  FooTactful.prototype.print = function(){
    console.log("Foo 的策略");
  }
  function BarTactful(){}
  BarTactful.prototype.print = function(){
    console.log("Bar 的策略");
  }

  var tactful = new Tactful()
  tactful.show(new FooTactful()) // Foo 的策略
  tactful.show(new BarTactful()) // Bar 的策略
2.6.2 案例:注册验证
  var validatalist = {
    notNull: function(value,bool){
      return (value !== '') == bool;
    },
    maxLength: function(value,maxLen){
      console.log(value, maxLen);
      return value.length < maxLen;
    },
    minLength: function(value,minLen){
      return value.length > minLen
    }
  }

  function AddValidata(id,opts){
    this.el = document.getElementById(id);
    this.opts = opts;
  }

  AddValidata.prototype.isPass = function(){
    for (var key in this.opts) {
      if (!validatalist[key](this.el.value, this.opts[key])) {
       return false;
      }
    }
    return true;
  }

  var v1 = new AddValidata('input',{
    notNull: true,
    maxLength: 12,
    minLength: 8
  })
  document.getElementById('btn').onclick = function(){
    console.log(v1.isPass());
  }

2.7 观察者模式(发布订阅模式)

2.7.1 作用

一个被观察者管理所有相依于它的观察者物件,并且在本身的状态改变时主动发出通知
eg:js中元素事件绑定其实就是一个观察者模式,绑定事件的元素就是被观察者,里边调用的所有函数都是观察者,触发事件其实就是在发布订阅

2.7.2 代码展示
  // 观察者模式(发布订阅模式)
  function Observer(){}

  // 绑定事件 订阅者
  /**
   * obj 订阅对象
   * events 事件
   * fn 回调函数
   */
  Observer.prototype.bind = function(obj,events,fn){
    obj.listeners = obj.listeners || {}
    obj.listeners[events] = obj.listeners[events] || []
    obj.listeners[events].push(fn)
  }

  // 发布事件
  Observer.prototype.fire = function(obj,events){
    var args = Array.prototype.slice.call(arguments).slice(2);
    for (let i = 0; i < obj.listeners[events].length; i++) {
      obj.listeners[events][i].apply(obj,args)
    }
  }
  
  var divObs = document.getElementById('div1');
  var objObserver = new Observer();
  objObserver.bind(divObs,'show',function(){
    console.log("123");
  })
  objObserver.bind(divObs,'show',function(){
    console.log("2345");
  })
  divObs.onclick = function(){
    objObserver.fire(divObs,'show'); // 打印依次输出:123,2345
  }
2.7.3 案例:改变div大小
  // 观察者模式(发布订阅模式)
  function Observer(){}

  // 绑定事件 订阅者
  /**
   * obj 订阅对象
   * events 事件
   * fn 回调函数
   */
  Observer.prototype.bind = function(obj,events,fn){
    obj.listeners = obj.listeners || {}
    obj.listeners[events] = obj.listeners[events] || []
    obj.listeners[events].push(fn)
  }

  // 发布事件
  Observer.prototype.fire = function(obj,events){
    var args = Array.prototype.slice.call(arguments).slice(2);
    for (let i = 0; i < obj.listeners[events].length; i++) {
      obj.listeners[events][i].apply(obj,args)
    }
  }
  
  var divObs = document.getElementById('div1');
  
  // 观察者模式(发布订阅模式) 案列---观察div大小改变情况
  function ScaleMethod(el){
    this.el = el;
    this.scale(); // 滑动
    this.wheel(); // 滚轮
  }
  ScaleMethod.prototype.scale = function(){
    var downX = 0;
    var downY = 0;
    var downW = 0;
    var downH = 0;
    var _this = this;
    this.el.onmousedown = function(e){
      downX = e.pageX;
      downY = e.pageY;
      downW = _this.el.offsetWidth;
      downH = _this.el.offsetHeight;

      document.onmousemove = function(e){
        _this.el.style.width = e.pageX - downX + 'px';
        _this.el.style.height = e.pageY - downY + 'px';
        objObserver.fire(_this, 'scale', _this.el.offsetWidth, _this.el.offsetHeight)
      }

      document.onmouseup = function(e){
        document.onmousemove = null;
        document.onmouseup = null;
      }
      return false
    }
  }

  ScaleMethod.prototype.wheel = function(){
    var _this = this;
    this.el.onmousewheel = function(e){
      if (e.wheelDelta > 0) {
        this.style.height = this.offsetHeight - 10 + 'px';
      }else{
        this.style.height = this.offsetHeight + 10 + 'px';
      }
      objObserver.fire(_this, 'scale', _this.el.offsetWidth, _this.el.offsetHeight)
    }
  }
  var objObserver = new Observer();
  var s1 = new ScaleMethod(divObs)
  objObserver.bind(s1,'scale',function(w,h){
    divObs.innerHTML = w + 'px,' + h + 'px';
  })

2.8 装饰者模式

2.8.1 作用

动态给一个对象添加一些额外的职责,对结果进行进一步的装饰

2.8.2 代码展示
  function DecorateFoo (){
    this.name = 'hello'
  }
  function DecorateBar (name){
    this.name = name + ' Javascript';
  }
  function DecorateBaz (name){
    this.name = name + ' !!!';
  }

  var decorate1 = new DecorateFoo();
  var decorate2 = new DecorateBar(decorate1.name);
  var decorate3 = new DecorateBaz(decorate2.name);
  console.log(decorate3.name); // hello Javascript !!!
2.8.3 案例:金额操作(添加千分符和类型)
function Moneys(number){
    this.number = number;
  }
  Moneys.prototype.get = function(){
    return this.number;
  }
  function Milles(num){
    this.number = this.set(num)
  }
  Milles.prototype.set = function(num){
    var reg = /(?=(?!\b)(\d{3})+(\.\d*)?$)/g;
    return num.toFixed(2).replace(reg,',')
  }
  Milles.prototype.get = function(){
    return this.number;
  }
  function Currency(number,type){
    this.number = this.set(number,type)
  }
  Currency.prototype.set = function(number,type){
    type = type || '¥';
    return type + number;
  }
  Currency.prototype.get = function(){
    return this.number;
  }

  function SetMoney(num, type){
    var m,mills,curr;
    if (type != undefined) {
      m1 = new Moneys(num);
      mills = new Milles(m1.get());
      curr = new Currency(mills.get(),type);
      return curr.get()
    }else{
      m1 = new Moneys(num);
      mills = new Milles(m1.get());
      curr = new Currency(mills.get());
      return curr.get()
    }
  }

  console.log(SetMoney(1234567890.145,'$')); // $1,234,567,890.14
  console.log(SetMoney(78913678.899)); // ¥78,913,678.90
  console.log(SetMoney(987423241.099,'$')); // $987,423,241.10

2.9 组合模式

2.9.1 作用

将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性

2.9.2 组合模式及其案列
  function Compose(name){
    this.name = name;
    this.childs = []
  }
  Compose.prototype.addChild = function(node){
    this.childs.push(node)
  }
  function ComposeChild(name){
    this.name = name;
  }

  function ShowRoot(node,parent){
    var li = document.createElement('li');
    li.innerHTML = node.name
    parent.appendChild(li)
    if (!node.childs) {
      return
    }
    for (let i = 0; i < node.childs.length; i++) {
      var ulChild = document.createElement('ul');
      li.appendChild(ulChild)
      ShowRoot(node.childs[i],ulChild)
    }
    console.log(li);
  }

  var root = new Compose("组合模式 html")
  var leafHead = new Compose("组合模式 head")
  root.addChild(leafHead)
  var leafBody = new Compose("组合模式 body")
  root.addChild(leafBody)
  var leafDiv1 = new Compose("组合模式  div1")
  leafBody.addChild(leafDiv1)
  var leafDiv2 = new Compose("组合模式  div2")
  leafBody.addChild(leafDiv2)
  var leafP = new ComposeChild("组合模式 p")
  leafDiv1.addChild(leafP)
  var leafSpan = new ComposeChild("组合模式 span")
  leafDiv1.addChild(leafSpan)
  var leafBtn = new ComposeChild("组合模式 button")
  leafDiv1.addChild(leafBtn)
  var leftTile = new ComposeChild("组合模式 title")
  leafHead.addChild(leftTile)
  var leafMeat = new ComposeChild("组合模式 meta")
  leafHead.addChild(leafMeat)
  var leafStyle = new ComposeChild("组合模式 style")
  leafHead.addChild(leafStyle)

  var divUl = document.getElementById('divUl')
  ShowRoot(root,divUl)
  // 点击具有子元素的元素时,进行展开或隐藏操作
  divUl.onclick = function(e){
    if (e.target.nodeName.toLowerCase() == 'li') {
      var child = e.target.children;
      for (let i = 0; i < child.length; i++) {
        if (child[i].nodeName.toLowerCase() == 'ul' && !child[i].flag) {
          child[i].style.display = "none";
          child[i].flag = true;
        }else if(child[i].nodeName.toLowerCase() == 'ul'){
          child[i].style.display = "block";
          child[i].flag = false;
        }
      }
    }
  }
2.9.2 案列效果图

组合模式效果图

2.10 备忘录模式

2.10.1 作用

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个形态,这样就可以将该对象恢复到原先保存的状态。

2.10.2 备忘录模式及其案列
  function Originator(){
    this.state = ''; // 状态
    this.memento = new Memento(); // 备忘录
  }

  Originator.prototype.getState = function(){ // 获取状态
    return this.state;
  }

  Originator.prototype.setState = function(state){ // 设置状态
    this.state = state;
  }

  Originator.prototype.createMemento = function(){ // 创建备忘录
    this.memento.setMemento(this.state)
  }

  Originator.prototype.restorMemento = function(){ // 还原备忘录
    this.setState(this.memento.getMemento())
  }

  function Memento(){
    this.state = [];
  }

  Memento.prototype.getMemento = function(){ // 获取备忘录
    return this.state.pop() || '';
  }

  Memento.prototype.setMemento = function(state){ // 设置备忘录
    this.state.push(state)
  }
  
  var o1 = new Originator()
  o1.setState("状态1");
  console.log("初始状态:"+o1.getState());
  o1.createMemento();
  o1.setState("状态2");
  console.log("改变后状态:"+o1.getState());
  o1.createMemento();
  o1.setState("状态3");
  console.log("改变后状态:"+o1.getState());
  o1.restorMemento();
  console.log("还原后状态:"+o1.getState());
  o1.restorMemento();
  console.log("还原后状态:"+o1.getState());

  var tips = document.getElementById('tips');
  var orig = document.getElementById('originator');
  var save = document.getElementById('save');
  var back = document.getElementById('back');
  var org = new Originator()

  save.onclick = function(){
    tips.innerHTML = "已保存";
    org.createMemento();
    org.setState(orig.value);
  }

  back.onclick = function(){
    org.restorMemento();
    orig.value = org.getState();
  }

  orig.oninput = function(){
    tips.innerHTML = "*";
  }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
前端框架中也可以应用设计模式来帮助开发人员更好地组织和管理代码。有一些常见的设计模式前端开发中被广泛使用,例如: 1. MVC模式(Model-View-Controller):MVC模式是一常见的架构模式,用于将应用程序的逻辑、数据和用户界面分离。在前端开发中,可以使用MVC模式来将数据、视图和控制器分离,以便更好地组织和管理代码。 2. 观察者模式(Observer Pattern):观察者模式用于实现对象之间的一对多依赖关系。在前端开发中,观察者模式可以用于实现事件监听和响应,例如当用户点击按钮时,触发相应的事件处理函数。 3. 单例模式(Singleton Pattern):单例模式用于确保一个类只有一个实例,并提供一个全局访问点。在前端开发中,单例模式可以用于管理全局状态、共享资源或提供统一的配置管理。 4. 工厂模式(Factory Pattern):工厂模式用于创建对象的过程中,将创建逻辑和具体对象的实现分离。在前端开发中,工厂模式可以用于创建不同类型的对象,例如根据用户的角色类型创建不同的导航菜单。 以上只是几个常见的设计模式前端开发中的应用,实际上还有更多的设计模式可以用于解决特定的问题。对于前端开发人员来说,了解不同的设计模式,并根据具体的需求进行选择和应用,可以帮助提高代码的可维护性和扩展性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [前端开发中常用的几设计模式](https://blog.csdn.net/shadowfall/article/details/112001884)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值