diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..aa7fbf2 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dc8a8cd --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +dp \ No newline at end of file diff --git a/Command/Command.md b/Command/Command.md index 1e49352..9004191 100644 --- a/Command/Command.md +++ b/Command/Command.md @@ -21,7 +21,7 @@
@@ -101,7 +101,7 @@ class DeleteMenu { ``` -之后我们分别实例华不同的对象 +之后我们分别实例化不同的对象 ```javascript // 首先获取按钮对象 diff --git a/Prototype/Prototype.md b/Prototype/Prototype.md index 6bf9868..3c66032 100644 --- a/Prototype/Prototype.md +++ b/Prototype/Prototype.md @@ -32,7 +32,7 @@ prototype 的几种方法 #### 1.Object.create()方法 -``` +```javascript let proto = {a:1} let propertiesObject = { b: { @@ -48,7 +48,7 @@ console.log(obj.__proto__ === proto); // true #### 2.方法继承 -``` +```javascript // 方法继承 let proto = function() {} proto.prototype.excute = function() {} @@ -60,14 +60,14 @@ child.prototype = new proto() #### 3.函数对Object的默认继承 -``` +```javascript let Foo = function() {} console.log(Foo.prototype.__proto__ === Object.prototype); // true ``` #### 4.isPrototypeOf -``` +```javascript prototypeObj.isPrototypeOf(obj) ``` @@ -77,7 +77,7 @@ prototypeObj.isPrototypeOf(obj) contructor.prototype是否出现在obj的原型链上 -``` +```javascript obj instanceof contructor ``` @@ -85,7 +85,7 @@ obj instanceof contructor Object.getPrototypeOf(obj) 方法返回指定对象obj的原型(内部[[Prototype]]属性的值) -``` +```javascript Object.getPrototypeOf(obj) ``` @@ -93,7 +93,7 @@ Object.getPrototypeOf(obj) 设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null -``` +```javascript var obj = {} var prototypeObj = {} Object.setPrototypeOf(obj, prototypeObj) diff --git a/README.md b/README.md index 6f53d97..7f863ba 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # JavaScript-DesignPatterns JavaScript设计模式的相关学习 +在线阅读地址: [JavaScript-DesignPatterns](https://reaperlee.cn/dp/) + ## 目录 ### 创建型 - [工厂模式](https://github.com/Reaper622/JavaScript-DesignPatterns/blob/master/Factory/Factory.md) @@ -19,6 +21,7 @@ JavaScript设计模式的相关学习 - [观察者模式](https://github.com/Reaper622/JavaScript-DesignPatterns/blob/master/Observer/Observer.md) - [命令模式](https://github.com/Reaper622/JavaScript-DesignPatterns/blob/master/Command/Command.md) - [状态模式](https://github.com/Reaper622/JavaScript-DesignPatterns/blob/master/State/State.md) +- [中介者模式](https://github.com/Reaper622/JavaScript-DesignPatterns/blob/master/Mediation/Mediation.md) diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js new file mode 100644 index 0000000..9220bcc --- /dev/null +++ b/docs/.vuepress/config.js @@ -0,0 +1,14 @@ +module.exports = { + title: 'JavaScript设计模式', + dest: './dp', + base: '/dp/', + repo: 'https://github.com/Reaper622/JavaScript-DesignPatterns', + themeConfig: { + // 添加导航栏 + nav: [ + {text: '设计模式', link: '/'}, + {text: '数据结构和算法', link: 'https://reaperlee.cn/ds-al'}, + {text: '博客', link: 'https://reaperlee.cn'}, + ] + } +} \ No newline at end of file diff --git a/docs/Adapter.md b/docs/Adapter.md new file mode 100644 index 0000000..221da83 --- /dev/null +++ b/docs/Adapter.md @@ -0,0 +1,74 @@ +# 适配器模式 + +> 适配器模式主要用来解决两个已有接口之间不匹配的问题,它不考虑这些接口是怎么实现的,也不考虑他们将来会如何演化。适配器模式不需要改变当前已有的接口,就能让他们协同作用。 + +适配器的别名也叫包装器(wrapper),这是一个并不复杂的模式,在日常开发中有许多这样的场景:例如当我们试图调用某个模块或者某个对象的接口时,却发现这个接口的格式并不符合目前的需求,这时就有两种解决方法,第一种使我们直接修改原来的接口实现,但如果原来的模块或者对象很复杂,亦或是我们拿到的已经是已压缩过的代码,那么去修改原接口就显得不现实了。第二种方法就是我们要讲到的适配器,将原接口转换成你希望拿到的接口,而你只需要通过适配器即可得到,并不需要去修改原模块或对象。 + +举一个抽象的例子,例如当我们有两台电脑需要充电: + +```javascript +class ThinkPad { + charge() { + console.log('ThinkPad 开始充电'); + } +} + + +class MacBook { + charge() { + console.log('MacBook 开始充电') + } +} +// 电源充电 +function PowerToCharge(laptop) { + if(laptop.charge instanceof Function) { + laptop.charge() + } +} + +PowerToCharge(new ThinkPad()) // ThinkPad开始充电 +PowerToCharge(new MacBook()) // MacBook开始充电 +``` + +但是如果MacBook不能直接用一种电源接口充电,可能我们就需要一种转接器,这里也就使用的适配器模式,我们不能直接更改电脑上的接口,但我们可以通过一层转接(封装),来实现充电 + +```javascript +class ThinkPad { + charge() { + console.log('ThinkPad 开始充电'); + } +} + + +class MacBook { + type_cCharge() { + console.log('MacBook 开始充电') + } +} + +// 定义适配器类,来实现对MacBook的转接 +class TypeCToDp { + charge() { + let macbook = new MacBook(); + return macbook.type_cCharge() + } +} +// 电源充电 +function PowerToCharge(laptop) { + if(laptop.charge instanceof Function) { + laptop.charge() + } +} + +PowerToCharge(new ThinkPad()) // ThinkPad开始充电 +PowerToCharge(new TypeCToDp()) // MacBook开始充电 +``` + + + +#### 总结 + +- 适配器模式虽然是一种相对简单的模式,但适配器在JS或者BFF层使用的场景很多。 +- 但同时,我们要意识到适配器模式其实一种补救措施,它用来解决的是一些古老不可维护或者已经在稳定版本的两个接口不兼容的问题,而在开发初期应该减少或者不使用这种模式,而是要规划好接口的一致性。 +- 适配器不会改变原有的接口,而是一个对象对另一个对象的包装。 +- 适配器模式符合开放封闭原则。 \ No newline at end of file diff --git a/docs/Appearance.md b/docs/Appearance.md new file mode 100644 index 0000000..082c784 --- /dev/null +++ b/docs/Appearance.md @@ -0,0 +1,55 @@ +# 外观模式 + +> 外观模式为一组复杂的子系统接口提供一个更高级的统一接口,通过这个接口使得对子系统接口的访问更容易,不符合单一职责原则和开放封闭原则。 + +其实外观模式很常见,它其实就是通过一个单独的函数,来简化对一个或多个更大型,更为复杂的函数的访问,是一种对复杂操作的封装。 + +### 封装Ajax + +初始化一个原生 Ajax 请求其实是复杂的,我们可以通过封装来简化 + +```javascript +function ajaxCall(type, url, callback, data) { + let xhr = (function(){ + try { + // 标准方法 + return new XMLHttpRequest() + }catch(e){} + + try { + return new ActiveXObject("Msxm12.XMLHTTP") + }catch(e){} + }()) + STATE_LOADED = 4 + STATUS_OK = 200 + + // 一但从服务器收到表示成功的相应消息,则执行所给定的回调方法 + xhr.onreadystatechange = function () { + if (xhr.readyState !== STATE_LOADED) { + return + } + if (xhr.state == STATUS_OK) { + callback(xhr.responseText) + } + } + + // 发出请求 + xhr.open(type.toUpperCase(), url) + xhr.send(data) +} +``` + +封装之后,我们发送请求的样子就变成了 + +```javascript +// 使用封装的方法 +ajaxCall("get", "/url/data", function(res) { + document.write(res) +}) +``` + + + +#### 总结 + + 外观模式适用于当需要同时有多个复杂操作时,通过把复杂操作封装,调用时直接用方法调用,提高代码的可阅读性和可维护性。 \ No newline at end of file diff --git a/docs/Command.md b/docs/Command.md new file mode 100644 index 0000000..9004191 --- /dev/null +++ b/docs/Command.md @@ -0,0 +1,136 @@ +# 命令模式 + +> 在软件系统里,`行为请求者`与`行为实现者`通常呈现一种*紧耦合*,但在某些场合,比如要对行为进行`记录、撤销/重做、事务`等处理时,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如果要将`行为请求者`与`行为实现者`解耦合,我们需要将一组行为抽象为对象,实现二者之间的松耦合,这就是`命令模式`。 + +我们需要在命令的发布者和接受者之间定义一个命令对象,命令对象会暴露一个统一的借口给命令的发布者而命令的发布者不需要去了解接受者是如何执行命令的,做到了命令发布者和接受者的解耦合。 + +[](https://imgchr.com/i/u06DRP) + +我们下面的例子中一个页面有三个按钮,每个按钮有不同的功能: + +```html + + +
+ + + +
+ +
+