分享

JavaScript-代理模式

 头号码甲 2021-07-24

代理模式

使用者无权访问目标对象
中间加代理,通过代理授权和控制

传统 UML 类图

JavaScript 中的代理模式

class ReadImg {
  constructor(fileName) {
    this.fileName = fileName;
    this.loadFromDisk();
  }
  display() {
    console.log("display..." + this.fileName);
  }
  loadFromDisk() {
    console.log("loading..." + this.fileName);
  }
}

class ProxyImg {
  constructor(fileName) {
    this.readImg = new ReadImg(fileName);
  }
  display() {
    this.readImg.display();
  }
}

// test
let proxyImg = new ProxyImg("1.png");
proxyImg.display();

应用场景

网页代理事件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <div>
      <a href="#">a1</a>
      <a href="#">a2</a>
      <a href="#">a3</a>
      <a href="#">a4</a>
      <a href="#">a5</a>
    </div>

    <script src="https://cdn./jQuery/3.3.0/jQuery"></script>
    <script>
      var div1 = document.getElementById("div1");
      div1.addEventListener("clink", function(e) {
        var target = e.target;
        if (target.nodeName === "A") {
          alert(target.innerHTML);
        }
      });
    </script>
  </body>
</html>

jQuery

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <div>
      <a href="#">a1</a>
      <a href="#">a2</a>
      <a href="#">a3</a>
      <a href="#">a4</a>
      <a href="#">a5</a>
    </div>

    <script src="https://cdn./jQuery/3.3.0/jQuery"></script>

    <script>
      $("#div1").click(function() {
        // this符合期望
        $(this).addClass("red");
      });
      $("#div1").click(function() {
        setTimeout(function() {
          // this不符合期望
          $(this).addClass("red");
        }, 1000);
      });
    </script>

    <script>
      // 如下方式解决
      $("#div1").click(function() {
        // this符合期望
        $(this).addClass("red");
      });
      $("#div1").click(function() {
        var _this = this;
        setTimeout(function() {
          // this符合期望
          $(this).addClass("red");
        }, 1000);
      });
    </script>
  </body>
</html>

$.proxy

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <div>
      <a href="#">a1</a>
      <a href="#">a2</a>
      <a href="#">a3</a>
      <a href="#">a4</a>
      <a href="#">a5</a>
    </div>

    <script src="https://cdn./jQuery/3.3.0/jQuery"></script>
    <script>
      $("#div1").click(function() {
        var fn = function() {
          $(this).css("background-color", "yellow");
        };
        fn = $.proxy(fn, this);
        setTimeout(fn, 1000);
      });
    </script>

    <script>
      // 由上面那个化简而来
      $("#div1").click(function() {
        fn = $.proxy(function() {
          $(this).css("background-color", "yellow");
        }, this);
        setTimeout(fn, 1000);
      });
    </script>

    <script>
      // 由上面那个化简而来
      $("#div1").click(function() {
        setTimeout(
          $.proxy(function() {
            $(this).css("background-color", "yellow");
          }, this),
          1000
        );
      });
    </script>
  </body>
</html>

es6 Proxy

明星和经纪人的关系

// 明星
let star = {
  name: "张XX",
  age: 25,
  phone: "13910733521"
};

// 经纪人
let agent = new Proxy(star, {
  get: function(target, key) {
    if (key === "phone") {
      // 返回经纪人自己的手机号
      return "18611112222";
    }
    if (key === "price") {
      // 明星不报价,经纪人报价
      return 120000;
    }
    return target[key];
  },
  set: function(target, key, val) {
    if (key === "customPrice") {
      if (val < 100000) {
        // 最低 10w
        throw new Error("价格太低");
      } else {
        target[key] = val;
        return true;
      }
    }
  }
});

// 主办方
console.log(agent.name);
console.log(agent.age);
console.log(agent.phone);
console.log(agent.price);

// 想自己提供报价(砍价,或者高价争抢)
agent.customPrice = 150000;
// agent.customPrice = 90000  // 报错:价格太低
console.log("customPrice", agent.customPrice);

设计原则验证

  • 代理类和目标类分离,隔离开目标类和使用者
  • 符合开放封闭原则

代理模式 VS 适配器模式

  • 适配器模式:提供一个不同的接口(如不同版本的插头)
  • 代理模式:提供一模一样的接口

代理模式 VS 装饰器模式

  • 装饰器模式:拓展功能,原有功能不变且可直接使用
  • 代理模式:显示原有功能,但经过限制或阉割之后的

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约