Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the design patterns in javascript?

2025-03-03 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

What are the specific design patterns in javascript? I believe many inexperienced people are at a loss about this. Therefore, this paper summarizes the causes and solutions of the problem. Through this article, I hope you can solve this problem.

The design patterns in javascript are: singleton pattern, policy pattern, agent pattern, iterator pattern, publish-subscribe pattern, command pattern, combination pattern, template method pattern, sharing meta-pattern, responsibility chain pattern, intermediary pattern, decorator pattern, state pattern, adapter pattern, appearance pattern and so on.

The operating environment of this tutorial: windows7 system, javascript1.8.5 version, Dell G3 computer.

Fifteen common design patterns in JavaScript

1. Singleton model

1. Define

Ensure that there is only one instance of a class and provide a global access point to it

two。 Core

Ensure that there is only one instance and provide global access

3. Realize

Suppose you want to set up an administrator and set it only once for multiple calls, we can use closures to cache an internal variable to implement this singleton.

Function SetManager (name) {this.manager = name;} SetManager.prototype.getName = function () {console.log (this.manager);}; var SingletonSetManager = (function () {var manager = null; return function (name) {if (! manager) {manager = new SetManager (name);} return manager;}}) (); SingletonSetManager ('a'). GetName () / / aSingletonSetManager ('b'). GetName (); / / aSingletonSetManager ('c'). GetName (); / / a

This is relatively simple, but what if we also set up a HR? You have to copy the code.

Therefore, you can rewrite the inside of the singleton to make it more general.

/ / extract the general singleton function getSingleton (fn) {var instance = null; return function () {if (! instance) {instance = fn.apply (this, arguments);} return instance;}}

If you call it again, the result will be the same.

/ / get singleton var managerSingleton = getSingleton (function (name) {var manager = new SetManager (name); return manager;}); managerSingleton ('a'). GetName (); / / amanagerSingleton ('b'). GetName (); / / amanagerSingleton ('c'). GetName (); / a

At this point, when we add HR, we don't need to change the implementation inside the singleton, we just need to implement what we need to do to add HR, and then call

Function SetHr (name) {this.hr = name;} SetHr.prototype.getName = function () {console.log (this.hr);}; var hrSingleton = getSingleton (function (name) {var hr = new SetHr (name); return hr;}); hrSingleton ('aa'). GetName (); / / aahrSingleton (' bb'). GetName (); / / aahrSingleton ('cc'). GetName (); / / aa

Or, if you just want to create a p layer, you don't need to instantiate the object and call the function directly.

The result is that there is only the first created p on the page

Function createPopup (html) {var div = document.createElement ('div'); div [XSS _ clean] = html; document.body.append (div); return div;} var popupSingleton = getSingleton (function () {var div = createPopup.apply (this, arguments); return div;}); console.log (popupSingleton (' aaa') [xss_clean], popupSingleton ('bbb') [xss_clean], popupSingleton (' bbb') [xss_clean]) / / aaa II. Strategy mode

1. Define

Define a series of algorithms, encapsulate them one by one, and make them interchangeable.

two。 Core

Separate the use of the algorithm from the implementation of the algorithm.

A program based on policy pattern consists of at least two parts:

The first part is a set of policy classes, which encapsulate specific algorithms and are responsible for the specific calculation process.

The second part is that the environment class Context,Context accepts the customer's request and then delegates the request to a policy class. To do this, it means that a reference to a policy object should be maintained in Context

3. Realize

Policy patterns can be used to combine a series of algorithms or a series of business rules

It is assumed that the final score of the student needs to be calculated through the grade, and each grade has a corresponding weight. We can define this group policy directly in the form of object literals.

/ / weighted mapping relation var levelMap = {S: 10, A: 8, B: 6, C: 4}; / / Group Policy var scoreLevel = {basicScore: 80, S: function () {return this.basicScore + levelMap ['S'];}, A: function () {return this.basicScore + levelMap ['A'] }, B: function () {return this.basicScore + levelMap ['B'];}, C: function () {return this.basicScore + levelMap ['C'];}} / / call function getScore (level) {return scoreLevel [level]? ScoreLevel [level] (): 0;} console.log (getScore ('S'), getScore ('A'), getScore ('B'), getScore ('C'), getScore ('D')); / 90 88 86 84 0

In terms of combining business rules, the more classic is the form validation method. The key parts are listed here.

/ / error prompt var errorMsgs = {default: 'incorrect input data format', minLength: 'insufficient input data length', isNumber: 'please enter a number', required: 'content is not empty'}; / / Rule set var rules = {minLength: function (value, length, errorMsg) {if (value.length)

< length) { return errorMsg || errorMsgs['minLength'] } }, isNumber: function(value, errorMsg) { if (!/\d+/.test(value)) { return errorMsg || errorMsgs['isNumber']; } }, required: function(value, errorMsg) { if (value === '') { return errorMsg || errorMsgs['required']; } }};// 校验器function Validator() { this.items = [];};Validator.prototype = { constructor: Validator, // 添加校验规则 add: function(value, rule, errorMsg) { var arg = [value]; if (rule.indexOf('minLength') !== -1) { var temp = rule.split(':'); arg.push(temp[1]); rule = temp[0]; } arg.push(errorMsg); this.items.push(function() { // 进行校验 return rules[rule].apply(this, arg); }); }, // 开始校验 start: function() { for (var i = 0; i < this.items.length; ++i) { var ret = this.items[i](); if (ret) { console.log(ret); // return ret; } } }};// 测试数据function testTel(val) { return val;}var validate = new Validator();validate.add(testTel('ccc'), 'isNumber', '只能为数字'); // 只能为数字validate.add(testTel(''), 'required'); // 内容不为空validate.add(testTel('123'), 'minLength:5', '最少5位'); // 最少5位validate.add(testTel('12345'), 'minLength:5', '最少5位');var ret = validate.start();console.log(ret); 4. 优缺点 优点 可以有效地避免多重条件语句,将一系列方法封装起来也更直观,利于维护 缺点 往往策略集会比较多,我们需要事先就了解定义好所有的情况 三、代理模式 1. 定义 为一个对象提供一个代用品或占位符,以便控制对它的访问 2. 核心 当客户不方便直接访问一个 对象或者不满足需要的时候,提供一个替身对象 来控制对这个对象的访问,客户实际上访问的是 替身对象。 替身对象对请求做出一些处理之后, 再把请求转交给本体对象 代理和本体的接口具有一致性,本体定义了关键功能,而代理是提供或拒绝对它的访问,或者在访问本体之前做一 些额外的事情 3. 实现 代理模式主要有三种:保护代理、虚拟代理、缓存代理 保护代理主要实现了访问主体的限制行为,以过滤字符作为简单的例子 // 主体,发送消息function sendMsg(msg) { console.log(msg);}// 代理,对消息进行过滤function proxySendMsg(msg) { // 无消息则直接返回 if (typeof msg === 'undefined') { console.log('deny'); return; } // 有消息则进行过滤 msg = ('' + msg).replace(/泥\s*煤/g, ''); sendMsg(msg);}sendMsg('泥煤呀泥 煤呀'); // 泥煤呀泥 煤呀proxySendMsg('泥煤呀泥 煤'); // 呀proxySendMsg(); // deny 它的意图很明显,在访问主体之前进行控制,没有消息的时候直接在代理中返回了,拒绝访问主体,这数据保护代理的形式 有消息的时候对敏感字符进行了处理,这属于虚拟代理的模式 虚拟代理在控制对主体的访问时,加入了一些额外的操作 在滚动事件触发的时候,也许不需要频繁触发,我们可以引入函数节流,这是一种虚拟代理的实现 // 函数防抖,频繁操作中不处理,直到操作完成之后(再过 delay 的时间)才一次性处理function debounce(fn, delay) { delay = delay || 200; var timer = null; return function() { var arg = arguments; // 每次操作时,清除上次的定时器 clearTimeout(timer); timer = null; // 定义新的定时器,一段时间后进行操作 timer = setTimeout(function() { fn.apply(this, arg); }, delay); }};var count = 0;// 主体function scrollHandle(e) { console.log(e.type, ++count); // scroll}// 代理var proxyScrollHandle = (function() { return debounce(scrollHandle, 500);})();_window.onscroll = proxyScrollHandle; 缓存代理可以为一些开销大的运算结果提供暂时的缓存,提升效率 来个栗子,缓存加法操作 // 主体function add() { var arg = [].slice.call(arguments); return arg.reduce(function(a, b) { return a + b; });}// 代理var proxyAdd = (function() { var cache = []; return function() { var arg = [].slice.call(arguments).join(','); // 如果有,则直接从缓存返回 if (cache[arg]) { return cache[arg]; } else { var ret = add.apply(this, arguments); return ret; } };})();console.log( add(1, 2, 3, 4), add(1, 2, 3, 4), proxyAdd(10, 20, 30, 40), proxyAdd(10, 20, 30, 40)); // 10 10 100 100四、迭代器模式 1. 定义 迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。 2. 核心 在使用迭代器模式之后,即使不关心对象的内部构造,也可以按顺序访问其中的每个元素 3. 实现 JS中数组的map forEach 已经内置了迭代器 [1, 2, 3].forEach(function(item, index, arr) { console.log(item, index, arr);}); 不过对于对象的遍历,往往不能与数组一样使用同一的遍历代码 我们可以封装一下 function each(obj, cb) { var value; if (Array.isArray(obj)) { for (var i = 0; i < obj.length; ++i) { value = cb.call(obj[i], i, obj[i]); if (value === false) { break; } } } else { for (var i in obj) { value = cb.call(obj[i], i, obj[i]); if (value === false) { break; } } }}each([1, 2, 3], function(index, value) { console.log(index, value);});each({a: 1, b: 2}, function(index, value) { console.log(index, value);});// 0 1// 1 2// 2 3// a 1// b 2 再来看一个例子,强行地使用迭代器,来了解一下迭代器也可以替换频繁的条件语句 虽然例子不太好,但在其他负责的分支判断情况下,也是值得考虑的 function getManager() { var year = new Date().getFullYear(); if (year = 2100) { console.log('C'); } else { console.log('B'); }}getManager(); // B 将每个条件语句拆分出逻辑函数,放入迭代器中迭代 function year2000() { var year = new Date().getFullYear(); if (year = 2100) { console.log('C'); } return false;}function year() { var year = new Date().getFullYear(); if (year >

2000 & & year

< 2100) { console.log('B'); } return false;}function iteratorYear() { for (var i = 0; i < arguments.length; ++i) { var ret = arguments[i](); if (ret !== false) { return ret; } }}var manager = iteratorYear(year2000, year2100, year); // B五、发布-订阅模式 1. 定义 也称作观察者模式,定义了对象间的一种一对多的依赖关系,当一个对象的状态发 生改变时,所有依赖于它的对象都将得到通知 2. 核心 取代对象之间硬编码的通知机制,一个对象不用再显式地调用另外一个对象的某个接口。 与传统的发布-订阅模式实现方式(将订阅者自身当成引用传入发布者)不同,在JS中通常使用注册回调函数的形式来订阅 3. 实现 JS中的事件就是经典的发布-订阅模式的实现 // 订阅document.body.addEventListener('click', function() { console.log('click1');}, false);document.body.addEventListener('click', function() { console.log('click2');}, false);// 发布document.body.click(); // click1 click2 自己实现一下 小A在公司C完成了笔试及面试,小B也在公司C完成了笔试。他们焦急地等待结果,每隔半天就电话询问公司C,导致公司C很不耐烦。 一种解决办法是 AB直接把联系方式留给C,有结果的话C自然会通知AB 这里的"询问"属于显示调用,"留给"属于订阅,"通知"属于发布 // 观察者var observer = { // 订阅集合 subscribes: [], // 订阅 subscribe: function(type, fn) { if (!this.subscribes[type]) { this.subscribes[type] = []; } // 收集订阅者的处理 typeof fn === 'function' && this.subscribes[type].push(fn); }, // 发布 可能会携带一些信息发布出去 publish: function() { var type = [].shift.call(arguments), fns = this.subscribes[type]; // 不存在的订阅类型,以及订阅时未传入处理回调的 if (!fns || !fns.length) { return; } // 挨个处理调用 for (var i = 0; i < fns.length; ++i) { fns[i].apply(this, arguments); } }, // 删除订阅 remove: function(type, fn) { // 删除全部 if (typeof type === 'undefined') { this.subscribes = []; return; } var fns = this.subscribes[type]; // 不存在的订阅类型,以及订阅时未传入处理回调的 if (!fns || !fns.length) { return; } if (typeof fn === 'undefined') { fns.length = 0; return; } // 挨个处理删除 for (var i = 0; i < fns.length; ++i) { if (fns[i] === fn) { fns.splice(i, 1); } } }};// 订阅岗位列表function jobListForA(jobs) { console.log('A', jobs);}function jobListForB(jobs) { console.log('B', jobs);}// A订阅了笔试成绩observer.subscribe('job', jobListForA);// B订阅了笔试成绩observer.subscribe('job', jobListForB);// A订阅了笔试成绩observer.subscribe('examinationA', function(score) { console.log(score);});// B订阅了笔试成绩observer.subscribe('examinationB', function(score) { console.log(score);});// A订阅了面试结果observer.subscribe('interviewA', function(result) { console.log(result);});observer.publish('examinationA', 100); // 100observer.publish('examinationB', 80); // 80observer.publish('interviewA', '备用'); // 备用observer.publish('job', ['前端', '后端', '测试']); // 输出A和B的岗位// B取消订阅了笔试成绩observer.remove('examinationB');// A都取消订阅了岗位observer.remove('job', jobListForA);observer.publish('examinationB', 80); // 没有可匹配的订阅,无输出observer.publish('job', ['前端', '后端', '测试']); // 输出B的岗位 4. 优缺点 优点 一为时间上的解耦,二为对象之间的解耦。可以用在异步编程中与MV*框架中 缺点 创建订阅者本身要消耗一定的时间和内存,订阅的处理函数不一定会被执行,驻留内存有性能开销 弱化了对象之间的联系,复杂的情况下可能会导致程序难以跟踪维护和理解 六、命令模式 1. 定义 用一种松耦合的方式来设计程序,使得请求发送者和请求接收者能够消除彼此之间的耦合关系 命令(command)指的是一个执行某些特定事情的指令 2. 核心 命令中带有execute执行、undo撤销、redo重做等相关命令方法,建议显示地指示这些方法名 3. 实现 简单的命令模式实现可以直接使用对象字面量的形式定义一个命令 var incrementCommand = { execute: function() { // something }}; 不过接下来的例子是一个自增命令,提供执行、撤销、重做功能 采用对象创建处理的方式,定义这个自增 // 自增function IncrementCommand() { // 当前值 this.val = 0; // 命令栈 this.stack = []; // 栈指针位置 this.stackPosition = -1;};IncrementCommand.prototype = { constructor: IncrementCommand, // 执行 execute: function() { this._clearRedo(); // 定义执行的处理 var command = function() { this.val += 2; }.bind(this); // 执行并缓存起来 command(); this.stack.push(command); this.stackPosition++; this.getValue(); }, canUndo: function() { return this.stackPosition >

= 0;}, canRedo: function () {return this.stackPosition

< this.stack.length - 1; }, // 撤销 undo: function() { if (!this.canUndo()) { return; } this.stackPosition--; // 命令的撤销,与执行的处理相反 var command = function() { this.val -= 2; }.bind(this); // 撤销后不需要缓存 command(); this.getValue(); }, // 重做 redo: function() { if (!this.canRedo()) { return; } // 执行栈顶的命令 this.stack[++this.stackPosition](); this.getValue(); }, // 在执行时,已经撤销的部分不能再重做 _clearRedo: function() { this.stack = this.stack.slice(0, this.stackPosition + 1); }, // 获取当前值 getValue: function() { console.log(this.val); }}; 再实例化进行测试,模拟执行、撤销、重做的操作 var incrementCommand = new IncrementCommand();// 模拟事件触发,执行命令var eventTrigger = { // 某个事件的处理中,直接调用命令的处理方法 increment: function() { incrementCommand.execute(); }, incrementUndo: function() { incrementCommand.undo(); }, incrementRedo: function() { incrementCommand.redo(); }};eventTrigger['increment'](); // 2eventTrigger['increment'](); // 4eventTrigger['incrementUndo'](); // 2eventTrigger['increment'](); // 4eventTrigger['incrementUndo'](); // 2eventTrigger['incrementUndo'](); // 0eventTrigger['incrementUndo'](); // 无输出eventTrigger['incrementRedo'](); // 2eventTrigger['incrementRedo'](); // 4eventTrigger['incrementRedo'](); // 无输出eventTrigger['increment'](); // 6 此外,还可以实现简单的宏命令(一系列命令的集合) var MacroCommand = { commands: [], add: function(command) { this.commands.push(command); return this; }, remove: function(command) { if (!command) { this.commands = []; return; } for (var i = 0; i < this.commands.length; ++i) { if (this.commands[i] === command) { this.commands.splice(i, 1); } } }, execute: function() { for (var i = 0; i < this.commands.length; ++i) { this.commands[i].execute(); } }};var showTime = { execute: function() { console.log('time'); }};var showName = { execute: function() { console.log('name'); }};var showAge = { execute: function() { console.log('age'); }};MacroCommand.add(showTime).add(showName).add(showAge);MacroCommand.remove(showName);MacroCommand.execute(); // time age七、组合模式 1. 定义 是用小的子对象来构建更大的 对象,而这些小的子对象本身也许是由更小 的"孙对象"构成的。 2. 核心 可以用树形结构来表示这种"部分- 整体"的层次结构。 调用组合对象 的execute方法,程序会递归调用组合对象 下面的叶对象的execute方法

Note, however, that the composition pattern is not a parent-child relationship, it is a HAS-A (aggregate) relationship that delegates the request to all the leaf objects it contains. Based on this delegation, it is necessary to ensure that the composite object and the leaf object have the same interface.

In addition, make sure that every leaf object in the list is treated in a consistent way, that is, the leaf object belongs to the same class and does not require too many special extra operations

3. Realize

Use combination mode to scan files in a folder

/ / folder combination object function Folder (name) {this.name = name; this.parent = null; this.files = [];} Folder.prototype = {constructor: Folder, add: function (file) {file.parent = this; this.files.push (file); return this }, scan: function () {/ / delegate processing for to leaf object (var I = 0; I

< this.files.length; ++i) { this.files[i].scan(); } }, remove: function(file) { if (typeof file === 'undefined') { this.files = []; return; } for (var i = 0; i < this.files.length; ++i) { if (this.files[i] === file) { this.files.splice(i, 1); } } }};// 文件 叶对象function File(name) { this.name = name; this.parent = null;}File.prototype = { constructor: File, add: function() { console.log('文件里面不能添加文件'); }, scan: function() { var name = [this.name]; var parent = this.parent; while (parent) { name.unshift(parent.name); parent = parent.parent; } console.log(name.join(' / ')); }}; 构造好组合对象与叶对象的关系后,实例化,在组合对象中插入组合或叶对象 var web = new Folder('Web');var fe = new Folder('前端');var css = new Folder('CSS');var js = new Folder('js');var rd = new Folder('后端');web.add(fe).add(rd);var file1 = new File('HTML权威指南.pdf');var file2 = new File('CSS权威指南.pdf');var file3 = new File('JavaScript权威指南.pdf');var file4 = new File('MySQL基础.pdf');var file5 = new File('Web安全.pdf');var file6 = new File('Linux菜鸟.pdf');css.add(file2);fe.add(file1).add(file3).add(css).add(js);rd.add(file4).add(file5);web.add(file6);rd.remove(file4);// 扫描web.scan(); 扫描结果为

4. Advantages and disadvantages

Advantages

It is convenient to construct a tree to represent the partial-overall structure of an object. After the construction of the tree is finally completed, the whole tree can be operated uniformly only through the top-level object of the request tree.

Shortcoming

The created objects all look alike, which may make the code difficult to understand, and creating too many objects can have some impact on performance.

VIII. Template method model

1. Define

The template method pattern consists of two parts: the first part is the abstract parent class, and the second part is the concrete implementation subclass.

two。 Core

Encapsulates the algorithmic framework of a subclass in an abstract parent class whose init method acts as a template for an algorithm that instructs the subclass to execute which methods in what order.

The public part is separated from the parent class, requiring the subclass to override the (volatile) abstract methods of some parent classes.

3. Realize

The template method pattern is generally implemented by inheritance

Taking motion as an example, motion has some general processing, which can be separated and implemented in the parent class. The particularity of a specific sport has its own class to rewrite the implementation.

Finally, the subclass directly calls the template function of the parent class to execute

/ / Sports function Sport () {} Sport.prototype = {constructor: Sport, / / template, execute init sequentially: function () {this.stretch (); this.jog (); this.deepBreath (); this.start (); var free = this.end () / / stretch if (free! = = false) {this.stretch ();}}, / / stretch stretch: function () {console.log ('stretch'), / / jog jog: function () {console.log () }, / / take a deep breath deepBreath: function () {console.log ('take a deep breath');}, / start motion start: function () {throw new Error ('subclass must override this method');}, / / end motion end: function () {console.log ('end of motion');}} / / Basketball function Basketball () {} Basketball.prototype = new Sport (); / / rewrite the related method Basketball.prototype.start = function () {console.log ('throw a few three pointers first');}; Basketball.prototype.end = function () {console.log ('exercise is over, take a step in advance'); return false;}; / Marathon function Marathon () {} Marathon.prototype = new Sport (); var basketball = new Basketball () Var marathon = new Marathon (); / / subclass calls will eventually execute basketball.init (); marathon.init () in the order defined by the parent class.

9. Enjoy the meta-model

1. Define

The flyweight pattern is a pattern for performance optimization. Its goal is to minimize the number of shared objects.

two。 Core

Use sharing technology to effectively support a large number of fine-grained objects.

It is emphasized that the attributes of the object are divided into internal state (attribute) and external state (attribute). The internal state is used for the sharing of objects, usually unchanged, while the external state is separated and determined by the specific scenario.

3. Realize

When a large number of similar objects are used in the program, the shared meta-pattern can be used to optimize and reduce the number of objects.

Take a chestnut, to measure the physical fitness of a class, only measure height and weight to judge.

/ / Health measurement function Fitness (name, sex, age, height, weight) {this.name = name; this.sex = sex; this.age = age; this.height = height; this.weight = weight;} / / start judging Fitness.prototype.judge = function () {var ret = this.name +':'; if (this.sex = 'male') {ret + = this.judgeMale () } else {ret + = this.judgeFemale ();} console.log (ret);}; / / male judgment rule Fitness.prototype.judgeMale = function () {var ratio = this.height / this.weight; return this.age > 20? (ratio > 3. 5): (ratio > 2. 8);}; / / female judgment rule Fitness.prototype.judgeFemale = function () {var ratio = this.height / this.weight; return this.age > 20? (ratio > 4): (ratio > 3);}; var a = new Fitness ('Agar,' male', 18,160,80); var b = new Fitness ('male', 21,180,70); var c = new Fitness (' compressed, 'female', 28,160,80); var d = new Fitness (' dating, 'male', 18,170,60); var e = new Fitness (' estranged, 'female', 18,160,40) / / start judging a.judge (); / A: falseb.judge (); / / B: falsec.judge (); / / C: falsed.judge (); / / D: truee.judge (); / / E: true

To judge five people, you need to create five objects, and a class has dozens of objects.

The common part of the object (internal state) can be extracted, independent of the external state. Gender can be regarded as the internal state, and other attributes belong to the external state.

So we only need to maintain both male and female objects (using factory objects), while other changes are maintained externally (using manager objects)

/ / Health measurement function Fitness (sex) {this.sex = sex;} / / Factory, create shareable objects var FitnessFactory = {objs: [], create: function (sex) {if (! this.objs [sex]) {this.objs [sex] = new Fitness (sex);} return this.objs [sex];}} / / Manager, manage the non-shared part var FitnessManager = {fitnessData: {}, / / add an add: function (name, sex, age, height, weight) {var fitness = FitnessFactory.create (sex) / / storing the changed data this.fitnessData [name] = {age: age, height: height, weight: weight}; return fitness;}, / / getting from the stored data and updating to the object updateFitnessData: function (name, obj) {var fitnessData = this.fitnessData [name] currently in use For (var item in fitnessData) {if (fitnessData.hasOwnProperty (item)) {obj [item] = fitnessData [item];}; / / start judging Fitness.prototype.judge = function (name) {/ / update the current state (obtained from the external state manager) FitnessManager.updateFitnessData (name, this) before starting the evaluation Var ret = name +':'; if (this.sex = 'male') {ret + = this.judgeMale ();} else {ret + = this.judgeFemale ();} console.log (ret);}; / / male judgment rule Fitness.prototype.judgeMale = function () {var ratio = this.height / this.weight; return this.age > 20? (ratio > 3. 5): (ratio > 2. 8);}; / / female judgment rule Fitness.prototype.judgeFemale = function () {var ratio = this.height / this.weight; return this.age > 20? (ratio > 4): (ratio > 3);}; var a = FitnessManager.add ('Agar,' male', 18,160,80); var b = FitnessManager.add ('male', 21,180,70); var c = FitnessManager.add (' compressed, 'female', 28,160,80); var d = FitnessManager.add (' dating, 'male', 18,170,60); var e = FitnessManager.add (' estranged, 'female', 18,160,40) / / start judging a.judge ('A'); / / A: falseb.judge ('B'); / / B: falsec.judge ('C'); / / C: falsed.judge ('D'); / / D: truee.judge ('E'); / / E: true

However, the code may be more complex, and this example may not be sufficient, but only shows how the shared meta pattern is implemented, which saves many similar objects, but with a few more operations.

The factory object is a bit like the singleton mode, except that it has an extra parameter of sex. If there is no internal state, the factory object without parameters is closer to the singleton mode.

X. responsibility chain model

1. Define

Give multiple objects the opportunity to process the request, thus avoiding the coupling between the sender and receiver of the request, join the objects into a chain, and pass the request along the chain until one object processes it

two。 Core

The request sender only needs to know the first node in the chain, weakens the strong connection between the sender and a group of receivers, and can easily add or delete a node in the responsibility chain. similarly, it is convenient to specify who is the first node.

3. Realize

Taking showing different types of variables as an example, setting up a chain of responsibilities can eliminate multiple if conditional branches.

/ / define an item in the chain function ChainItem (fn) {this.fn = fn; this.next = null;} ChainItem.prototype = {constructor: ChainItem, / / set the next setNext: function (next) {this.next = next; return next;}, / / start execution of start: function () {this.fn.apply (this, arguments) }, / / go to the next item in the chain to execute toNext: function () {if (this.next) {this.start.apply (this.next, arguments);} else {console.log ('no matching execution items');} / / display digital function showNumber (num) {if (typeof num = 'number') {console.log (' number', num);} else {/ / transfer to the next this.toNext (num);}} / / display string function showString (str) {if (typeof str = 'string') {console.log (' string', str) } else {this.toNext (str);}} / / display object function showObject (obj) {if (typeof obj = 'object') {console.log (' object', obj);} else {this.toNext (obj);}} var chainNumber = new ChainItem (showNumber); var chainString = new ChainItem (showString); var chainObject = new ChainItem (showObject); / / set chain chainObject.setNext (chainNumber) .setNext (chainString) ChainString.start ('12'); / / string 12chainNumber.start ({}); / / No matching execution project chainObject.start ({}); / / object {} chainObject.start (123); / / number 123

At this time, when you want to judge that it is not defined, you can add it directly to the chain.

/ / Show undefined function showUndefined (obj) {if (typeof obj = = 'undefined') {console.log (' undefined');} else {this.toNext (obj);}} var chainUndefined = new ChainItem (showUndefined); chainString.setNext (chainUndefined); chainNumber.start (); / / undefined

As can be seen from the example, after using the responsibility chain, it has been changed from the original conditional branch to a lot of objects. Although the structure is clearer, it may affect the performance to a certain extent, so we should pay attention to avoid too long responsibility chain.

11. Intermediary model

1. Define

All related objects communicate through intermediary objects instead of referencing each other, so when an object changes, you only need to notify the intermediary object.

two。 Core

Turns the reticulated many-to-many relationship into a relatively simple one-to-many relationship (complex scheduling processing is left to intermediaries)

After using an intermediary

3. Realize

Multiple objects do not have to be instantiated objects, but can also be understood as multiple items independent of each other. When these items are being processed, they need to be known and processed through the data of other items.

If each item is processed directly, the program will be very complex, and if you modify a place, you have to modify it within multiple items.

We extract this process and package it into an intermediary to deal with it, and when everything needs to be dealt with, we can notify the intermediary.

Var A = {score: 10, changeTo: function (score) {this.score = score; / / get this.getRank () by yourself;}, / / get getRank directly: function () {var scores = [this.score, B.score, C.score] .sort (function (a, b) {return a

< b; }); console.log(scores.indexOf(this.score) + 1); }};var B = { score: 20, changeTo: function(score) { this.score = score; // 通过中介者获取 rankMediator(B); }};var C = { score: 30, changeTo: function(score) { this.score = score; rankMediator(C); }};// 中介者,计算排名function rankMediator(person) { var scores = [A.score, B.score, C.score].sort(function(a, b) { return a < b; }); console.log(scores.indexOf(person.score) + 1);}// A通过自身来处理A.changeTo(100); // 1// B和C交由中介者处理B.changeTo(200); // 1C.changeTo(50); // 3 ABC三个人分数改变后想要知道自己的排名,在A中自己处理,而B和C使用了中介者。B和C将更为轻松,整体代码也更简洁 最后,虽然中介者做到了对模块和对象的解耦,但有时对象之间的关系并非一定要解耦,强行使用中介者来整合,可能会使代码更为繁琐,需要注意。 十二、装饰者模式 1. 定义 以动态地给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象。 是一种"即用即付"的方式,能够在不改变对 象自身的基础上,在程序运行期间给对象动态地 添加职责 2. 核心 是为对象动态加入行为,经过多重包装,可以形成一条装饰链 3. 实现 最简单的装饰者,就是重写对象的属性 var A = { score: 10};A.score = '分数:' + A.score; 可以使用传统面向对象的方法来实现装饰,添加技能 function Person() {}Person.prototype.skill = function() { console.log('数学');};// 装饰器,还会音乐function MusicDecorator(person) { this.person = person;}MusicDecorator.prototype.skill = function() { this.person.skill(); console.log('音乐');};// 装饰器,还会跑步function RunDecorator(person) { this.person = person;}RunDecorator.prototype.skill = function() { this.person.skill(); console.log('跑步');};var person = new Person();// 装饰一下var person1 = new MusicDecorator(person);person1 = new RunDecorator(person1);person.skill(); // 数学person1.skill(); // 数学 音乐 跑步 在JS中,函数为一等对象,所以我们也可以使用更通用的装饰函数 // 装饰器,在当前函数执行前先执行另一个函数function decoratorBefore(fn, beforeFn) { return function() { var ret = beforeFn.apply(this, arguments); // 在前一个函数中判断,不需要执行当前函数 if (ret !== false) { fn.apply(this, arguments); } };}function skill() { console.log('数学');}function skillMusic() { console.log('音乐');}function skillRun() { console.log('跑步');}var skillDecorator = decoratorBefore(skill, skillMusic);skillDecorator = decoratorBefore(skillDecorator, skillRun);skillDecorator(); // 跑步 音乐 数学十三、状态模式 1. 定义 事物内部状态的改变往往会带来事物的行为改变。在处理的时候,将这个处理委托给当前的状态对象即可,该状态对象会负责渲染它自身的行为 2. 核心 区分事物内部的状态,把事物的每种状态都封装成单独的类,跟此种状态有关的行为都被封装在这个类的内部 3. 实现 以一个人的工作状态作为例子,在刚醒、精神、疲倦几个状态中切换着 // 工作状态function Work(name) { this.name = name; this.currentState = null; // 工作状态,保存为对应状态对象 this.wakeUpState = new WakeUpState(this); // 精神饱满 this.energeticState = new EnergeticState(this); // 疲倦 this.tiredState = new TiredState(this); this.init();}Work.prototype.init = function() { this.currentState = this.wakeUpState; // 点击事件,用于触发更新状态 document.body.onclick = () =>

{this.currentState.behaviour ();};}; / / Update work status Work.prototype.setState = function (state) {this.currentState = state;} / / just wake up function WakeUpState (work) {this.work = work;} / / newly awakened behavior WakeUpState.prototype.behaviour = function () {console.log (this.work.name,':', 'just wake up, sleep in first') / / I only slept for 2 seconds and then I was refreshed. SetTimeout (() = > {this.work.setState (this.work.energeticState);}, 2 * 1000);} / / energetic function EnergeticState (work) {this.work = work;} EnergeticState.prototype.behaviour = function () {console.log (this.work.name,':', 'super spiritual') / / setTimeout (() = > {this.work.setState (this.work.tiredState);}, 1000);}; / / tired function TiredState (work) {this.work = work;} TiredState.prototype.behaviour = function () {console.log (this.work.name,':', 'how fat, so sleepy') / / unconsciously, it becomes a state of waking again. SetTimeout (()) = > {this.work.setState (this.work.wakeUpState);}, 1000);}; var work = new Work ('Cao Cao')

Click the page to trigger the action to update the status

4. Advantages and disadvantages

Advantages

The logic of state switching is distributed in the state class, which is easy to maintain.

Shortcoming

Multiple state classes are also a disadvantage for performance, which can be further optimized using the shared meta pattern

If the logic is scattered among the state classes, it may not be easy to see the change logic of the state machine.

XIV. Adapter mode

1. Define

It is to solve the problem of incompatible interfaces between two software entities, and to adapt the incompatible parts.

two。 Core

Solve the problem of mismatch between two existing interfaces

3. Realize

For example, a simple adapter for data format conversion

/ / render data in a format limited to array function renderData (data) {data.forEach (function (item) {console.log (item);});} / / A pair of non-array conversion adapters function arrayAdapter (data) {if (typeof data! = = 'object') {return [];} if (Object.prototype.toString.call (data) =' [object Array]') {return data } var temp = []; for (var item in data) {if (data.hasOwnProperty (item)) {temp.push (data [item]);}} return temp;} var data = {0: 'awful, 1:' baked, 2:'C'}; renderData (arrayAdapter (data)); / / A B C XV, appearance mode

1. Define

Provide a consistent interface for a set of interfaces in the subsystem and define a high-level interface that makes the subsystem easier to use

two。 Core

You can access the subsystem by requesting the appearance interface, or you can choose to access the subsystem directly beyond the appearance.

3. Realize

The appearance pattern in JS can be thought of as a collection of functions.

/ / three processing functions function start () {console.log ('start');} function doing () {console.log (' doing');} function end () {console.log ('end');} / / appearance function to unify some processing and facilitate calling function execute () {start (); doing (); end () } / / call init to start the execution of function init () {/ / the high-level function is called directly here, or you can choose to directly call the relevant function execute ();} init (); / / start doing end after reading the above, have you mastered the specific methods of the design patterns in javascript? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report