当前位置:   article > 正文

前端常用的设计模式_前端设计模式

前端设计模式

这里就按23中常见设计模式的顺序来展示前端一些常用的设计方法。

本文主要参考 《js设计模式与实践开发》

1. 单例模式

实现一个标准的单例模式并不复杂,无非是用一个变量来标志当前是否已经为某个类创建 过对象,如果是,则在下一次获取该类的实例时,直接返回之前创建的对象。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <script>
  11. //多个实例控制同一个变量内容 节省资源
  12. function Resource() {
  13. if (Resource.instance) {
  14. return Resource.instance
  15. }
  16. else {
  17. this.balance = 100
  18. Resource.instance = this
  19. }
  20. }
  21. Resource.prototype.pay = function (money) {
  22. let remain = this.balance - money
  23. if (remain >= 0) {
  24. this.balance = remain
  25. console.log("消费成功,余额为" + this.balance);
  26. } else {
  27. throw "余额不足"
  28. }
  29. }
  30. var r1 = new Resource()
  31. r1.pay(20)
  32. var r2 = new Resource()
  33. r2.pay(30)
  34. </script>
  35. </body>
  36. </html>

单例模式同样也有一些特殊的实现方法

  1. var CreateDiv = function( html ){
  2. this.html = html;
  3. this.init();
  4. };
  5. CreateDiv.prototype.init = function(){
  6. var div = document.createElement( 'div' );
  7. div.innerHTML = this.html;
  8. document.body.appendChild( div );
  9. };
  10. //接下来引入代理类 proxySingletonCreateDiv:
  11. var ProxySingletonCreateDiv = (function(){
  12. var instance;
  13. return function( html ){
  14. if ( !instance ){
  15. instance = new CreateDiv( html );
  16. }
  17. return instance;
  18. }
  19. })();
  20. var a = new ProxySingletonCreateDiv( 'sven1' );
  21. var b = new ProxySingletonCreateDiv( 'sven2' );
  22. alert ( a === b );

将单例实现交给代理类,而把原本的类变成一个普通类。

单例模式的应用主要包括两点,第一是节省资源,避免创建多个实例,第二个就是为了让多个new出来的实例(其实还是一个实例只是多个变量)共同管理同一些状态,比如多个人消费同一笔钱等。

2. 策略模式

先看一个例子

  1. var calculateBonus = function( performanceLevel, salary ){
  2. if ( performanceLevel === 'S' ){
  3. return salary * 4;
  4. }
  5. if ( performanceLevel === 'A' ){
  6. return salary * 3;
  7. }
  8. if ( performanceLevel === 'B' ){
  9. return salary * 2;
  10. }
  11. };
  12. calculateBonus( 'B', 20000 ); // 输出:40000
  13. calculateBonus( 'S', 6000 ); // 输出:24000

这就是策略模式解决的典型问题,当存在多个if else判断情况时,代码会变得臃肿而且难以管理。

使用策略模式重构

策略模式指的是定义一系 列的算法,把它们一个个封装起来。将不变的部分和变化的部分隔开是每个设计模式的主题,策 略模式也不例外,策略模式的目的就是将算法的使用与算法的实现分离开来。

  1. //去除大量重复的情况判断。
  2. var strategies = {
  3. "S": function (salary) {
  4. return salary * 4;
  5. },
  6. "A": function (salary) {
  7. return salary * 3;
  8. },
  9. "B": function (salary) {
  10. return salary * 2;
  11. }
  12. };
  13. var calculateBonus = function (level, salary) {
  14. return strategies[level](salary);
  15. };
  16. console.log(calculateBonus('S', 20000)); // 输出:80000
  17. console.log(calculateBonus('A', 10000)); // 输出:30000

3. 代理模式

代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。

代理模式分为两大应用:

第一个是保护代理:即代理会滤掉一些特殊的请求,特殊的条件保证原行为执行的成功性。

第二个是虚拟代理:将一些开销大的操作延迟到需要执行时执行。

保护代理用于控制不同权限的对象对目标对象的访问,但在 JavaScript 并不容易实现保护代 理,因为我们无法判断谁访问了某个对象。而虚拟代理是最常用的一种代理模式,本章主要讨论 的也是虚拟代理。

代理模式包括许多小分类,在 JavaScript 开发中最常用的是虚拟代理和缓存代理。

缓存代理

  1. /**************** 计算乘积 *****************/
  2. var mult = function () {
  3. var a = 1;
  4. for (var i = 0, l = arguments.length; i < l; i++) {
  5. a = a * arguments[i];
  6. }
  7. return a;
  8. };
  9. /**************** 计算加和 *****************/
  10. var plus = function () {
  11. var a = 0;
  12. for (var i = 0, l = arguments.length; i < l; i++) {
  13. a = a + arguments[i];
  14. }
  15. return a;
  16. };
  17. /**************** 创建缓存代理的工厂 *****************/
  18. var createProxyFactory = function (fn) {
  19. var cache = {};
  20. return function () {
  21. var args = Array.prototype.join.call(arguments, ',');
  22. if (args in cache) {
  23. return cache[args];
  24. }
  25. return cache[args] = fn.apply(this, arguments);
  26. }
  27. };
  28. var proxyMult = createProxyFactory(mult),
  29. proxyPlus = createProxyFactory(plus);
  30. alert(proxyMult(1, 2, 3, 4)); // 输出:24
  31. alert(proxyMult(1, 2, 3, 4)); // 输出:24
  32. alert(proxyPlus(1, 2, 3, 4)); // 输出:10
  33. alert(proxyPlus(1, 2, 3, 4)); // 输出:10

4. 迭代器模式

迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象 的内部表示。迭代器模式可以把迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即 使不关心对象的内部构造,也可以按顺序访问其中的每个元素。

应用不是特别多 给个例子就行

  1. var each = function( ary, callback ){
  2. for ( var i = 0, l = ary.length; i < l; i++ ){
  3. callback.call( ary[i], i, ary[ i ] ); // 把下标和元素当作参数传给 callback 函数
  4. }
  5. };
  6. each( [ 1, 2, 3 ], function( i, n ){
  7. alert ( [ i, n ] );
  8. });

5. 发布订阅模式

这个模式应该是前端最熟悉的设计模式之一。

这里模拟一个发布订阅模式的简单实现,(包含单例模式,为了让多个变量控制同一个线程池)

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>Document</title>
  8. </head>
  9. <body>
  10. <script>
  11. function Pubsub() {
  12. if (Pubsub.instance) {
  13. return Pubsub.instance
  14. } else {
  15. this.prob = {}
  16. Pubsub.instance = this
  17. }
  18. }
  19. Pubsub.prototype.publish = function (msg) {
  20. if (Object.keys(this.prob).includes(msg)) {
  21. for (let item of this.prob[msg]) {
  22. item.callback.call(item.target)
  23. }
  24. }
  25. }
  26. Pubsub.prototype.subscribe = function (target, msg, callback) {
  27. if (Object.keys(this.prob).includes(msg)) {
  28. this.prob[msg].push({ target, callback })
  29. } else {
  30. this.prob[msg] = [{ target, callback }]
  31. }
  32. }
  33. Pubsub.prototype.delete = function (target, msg) {
  34. if (Object.keys(this.prob).includes(msg)) {
  35. let probItem = this.prob[msg].filter(item => {
  36. return item.target != target
  37. })
  38. if (probItem.length === 0) {
  39. delete this.prob[msg]
  40. } else {
  41. this.prob[msg] = probItem
  42. }
  43. }
  44. }
  45. let pubsub = new Pubsub()
  46. let target1 = { flag: "1" }
  47. pubsub.subscribe(target1, "aaa", function () {
  48. console.log(this.flag);
  49. })
  50. pubsub.publish("aaa")
  51. let pubsub2 = new Pubsub()
  52. let target2 = { flag: "2" }
  53. pubsub2.subscribe(target2, "bbb", function () {
  54. console.log(this.flag);
  55. })
  56. pubsub2.publish("aaa")
  57. pubsub2.publish("bbb")
  58. pubsub.delete(target2, "bbb")
  59. console.log(pubsub);
  60. </script>
  61. </body>
  62. </html>

6. 命令模式

命令模式是最简单和优雅的模式之一,命令模式中的命令(command)指的是一个执行某些 特定事情的指令。

宏命令 一条命令执行多个具体任务。

  1. var MacroCommand = function () {
  2. return {
  3. commandsList: [],
  4. add: function (command) {
  5. this.commandsList.push(command);
  6. },
  7. execute: function () {
  8. for (var i = 0, command; command = this.commandsList[i++];) {
  9. command.execute();
  10. }
  11. }
  12. }
  13. };
  14. var macroCommand = MacroCommand();
  15. macroCommand.add(closeDoorCommand);
  16. macroCommand.add(openPcCommand);
  17. macroCommand.add(openQQCommand);
  18. macroCommand.execute();

和发布订阅蛮像的。

7. 组合模式

组合模式将对象组合成树形结构,以表示“部分整体”的层次结构。 除了用来表示树形结 构之外,组合模式的另一个好处是通过对象的多态性表现,使得用户对单个对象和组合对象的使 用具有一致性。

  1. var closeDoorCommand = {
  2. execute: function(){
  3. console.log( '关门' );
  4. }
  5. };
  6. var openPcCommand = {
  7. execute: function(){
  8. console.log( '开电脑' );
  9. }
  10. };
  11. var openQQCommand = {
  12. execute: function(){
  13. console.log( '登录 QQ' );
  14. }
  15. };
  16. var MacroCommand = function(){
  17. return {
  18. commandsList: [],
  19. add: function( command ){
  20. this.commandsList.push( command );
  21. },
  22. execute: function(){
  23. for ( var i = 0, command; command = this.commandsList[ i++ ]; ){
  24. command.execute();
  25. }
  26. }
  27. }
  28. };
  29. var macroCommand = MacroCommand();
  30. macroCommand.add( closeDoorCommand );
  31. macroCommand.add( openPcCommand );
  32. macroCommand.add( openQQCommand );
  33. macroCommand.execute();

8. 模板方法模式和享元模式

这两个放在一起说是因为他们在js中的应用比较常见,基本都是一起使用。

模板方法指的最明确的例子就是继承,父类是模板,子类为多个使用该模板的例子。

指享元模式的核心是运用共享技术来有效支持大量细粒度的对象。

能复用的属性对象就复用没必要一直创建,典型的例子就是可以使用原型链创建方法而并非直接向构造函数里添加,或者是使用类变量。

9. 职责链模式

职责链模式的定义是:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间 的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

从这两个例子中,我们很容易找到职责链模式的最大优点:请求发送者只需要知道链中的第 一个节点,从而弱化了发送者和一组接收者之间的强联系。如果不使用职责链模式,那么在公交 车上,我就得先搞清楚谁是售票员,才能把硬币递给他。同样,在期末考试中,也许我就要先了 解同学中有哪些可以解答这道题。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/556099
推荐阅读
相关标签
  

闽ICP备14008679号