什么是设计模式?
它到底有什么作用?在程序员的核心竞争力——如何写出更好的代码中,它又扮演了什么样的作用?
其实设计模式并不是1995年诞生的那部《设计模式》才出现,实际上,它无所不在,在此之前,可能很多那个年代的前辈,已经不知不觉中在广泛的应用它了。而首次提出设计模式概念的GoF,其实他们仅仅只做了一件事,那就是把市面上现有的优秀代码设计方案起了个名。
我并非科班出身,还记得曾经写过的关于算法入门的一篇文章中说到,在一次面试的过程中,我被一个冒泡排序问倒了。。。然而事实上却是在一些逻辑处理上用过很多次,而这在接触冒泡之前,我并不知晓。然而就代表不会吗?不,冒泡、选择、插入甚至什么希尔、归并、堆名字被叫成啥都可以不管,因为这些仅仅只是一个名字,而理解为什么这样更好,为什么它会更快才是核心所在。
就如之前,并不懂什么叫策略模式,但完全不妨碍我采用对象key-value(case-solution)的码代码方式。不懂这些概念有什么关系吗?没有,假如策略被叫做方案池,策略模式就不是策略模式了吗?你代码的应用方式就变了吗?不会。它还是它,并不会因为一个名字而改变什么,也不是什么高深的东西。
而且我相信,设计模式也不会简简单单只有23种,之所以说23种,仅仅是因为当时的作者遇到过的优秀的代码设计方式刚好有23种,而有可能你一直在采用的某种很好的写代码的方式,只是你不知道要怎么表达它。
但为什么还要说设计模式呢?因为给了它起了个名字,才更利于传播和推广。我不再需要因为没文化而非常费脑力的为你讲解,我看到的那个轮廓是什么?
好了,好像有点扯远了。
这里不想讲什么设计模式6大原则,23大设计模式等等。。。这些我也不会其实= =这里只想描述那有些模糊的轮廓。
上篇先聊3个吧,不然篇幅太长。
先来说一下工厂(factory)
相信很多框架,或一些较大型的UI库组件库,甚至一些功能较复杂的插件源码中,你可以看到很多参数传的是factory?也就是工厂,参数肯定是要语义化的,那为什么是factory?
尽管这跟工厂模式还有些差异,但这个框架,实际上就是一个大工厂,它可以给你造炮弹,同时还可以给你造弹药,(如JQuery可以给你提供query,同时还提供各类强大的拓展功能函数比如ajax、extend、proxy、each等等,这些其实都是一个个的产品,一个个被工厂生产出来的产品)
一开始,每一种类型的工厂就像社会分工大环境某一个细分领域下的工匠,它可能只能完成特定的事情。比如一个加减乘除,可能有些简单的工厂只能完成这个事情。
// 简单工厂模式: 厂长 => 员工 simpleFactory (type) { switch(type) { case '+' : console.log('这是加法运算'); break; case '-' : console.log('这是减法运算'); break; case '*' : console.log('这是乘法运算'); break; case '/' : console.log('这是除法运算'); break; } },
而有时候为了使代码更加低耦合,就不在在这里面写:console.log('这是加法运算')这样的具体实现代码,而是用一个方法包裹起来,而此类的工厂模式则叫做工厂方法模式
// 工厂方法模式: 厂长 => 主管 => 员工 factoryModule (type) { switch (type) { case '+' : this.add(); break; case '-' : this.sub(); break; case '*' : this.multip(); break; case '/' : this.division(); break; } }, add () { console.log('这是加法运算'); }, sub () { console.log('这是减法运算'); }, multip () { console.log('这是乘法运算'); }, division () { console.log('这是除法运算'); },
但有时候这个工厂很大,它变成了一个集团(已经不再是很具体干啥事了,它变成了抽象工厂模式),比如三星,在它的指挥中心总部(注册中心)下属还分了三星电子,三星网络,三星重工,三星航空,三星物产...但这个大的集团,这个大的工厂,它实际上还是由很多很多的小工厂组成,只不过这些工厂在总部做了注册,做了登记,并且向它汇报财报,盈亏等等。
// 抽象工厂模式: 老板 => 厂长 => 主管 => 员工 abstractFactory () { // 这是集团的指挥中心 this.factoryModule(); // 它可能仅仅变成了这样;每一个厂长每天来坐下工作汇报就行了,其余的不管 // ... others factoryModule }
再来看下什么是策略?
在平时的写代码中,经常用到各种条件判断对吧?此时你可能做的就是将条件一一判断,比如if,比如三目运算符。但你没觉得很烦吗?
比如下面的代码:
function judge (len) { if(len > 1) { console.log('len > 1'); } else if (len > 2) { console.log('len > 2'); } else if (len > 3) { console.log('len > 2'); } // else if ... if ... }
而这时候一种很好的方式就是采用策略模式来设计代码,你可以简单理解成key-values,尽管它不仅仅是这样:
看一下代码:
// 策略模式 Strategy () { const casePool = { case1: () => { console.log('this is the solution of the case1'); }, case2: () => { console.log('this is the solution of the case2'); } //... } // 外部调用 如:casePool['case1']() },
其实,策略模式,就是一种应对策略,一种问题-解决方案、问题-解决方案...当此类的问题很多时,一个个解决方案聚合而成的方案池。当你遇到这种问题的时候,哦,从方案池中找到对应的解决办法,而我们通常来说,叫做应对策略。
再来看一下观察者模式(Observer)
登高而能望远,这是每一个爬山爱好者最享受的一件事。那望远之后呢?除了把握下方川流不息的人流车流,给予你一种一切尽在掌握的错觉之外,还有什么?观察之后要干什么?那就是update,更新,也许你更新了对高山周围地貌的看法,也许你明白了你为之奋斗半生的一套房子实际上仅仅是某一个很小的角落下某一层中的某一个小房门之后的那个小方块,也许还有其他。。而这就是观察者模式。
我们看一下观察者的代码结构实现:
Observer () { function observer () { this.observerList = []; } observer.prototype = { add (key) { this.observerList.push(key); }, remove (key) { return this.observerList.filter(item => item != key); }, // 谁观察到变化了就更新谁 update (data) { this.observerList.forEach(item => { item(data); }); } } let observer1 = function (data) { console.log('我是observer1, 我观察到数据更新了,变成:' + data); } let observer2 = function (data) { console.log('我是observer2, 我观察到数据更新了,变成:' + data); } var o = new observer; o.add(observer1); o.add(observer2); o.update('哈哈哈'); o.update('我又更新了哦'); }
我们经常用JavaScript来对页面的event做监听,一个个的addEventListener,对吧,其实这些监听都是一个个的观察者。
观察者模式有不少变种,在Vue越来越受欢迎的今天,你也可能看到了很多这部分的内容,甚至也可能在平时的学习中,在面试中已经接触到了,那就是订阅-发布模式,订阅发布其实是观察者模式的一个变种,你对某一个主题的东西做了订阅,这个主题有新消息时,指挥中心把新消息发布给你,而观察者呢?它是你主动去观察,积极去观察那份新的变化,整个主体目标摆在那供你看,供你观察,从而做更新。而这实际上干的事是一样的,输出的结果是一致的。甚至后续的黑板模式,作为订阅者你还可以参与到内容的修改、建设之中,你是分布式的,而这在我看来这都是观察者模式的变种。
而其实在我看来,不管是工厂,还是策略或者是观察者,它都是脱离了原有的个体经营,变成了聚合式的,集群式的改变(单个的改变 => 群体的改变),而大多时候,我们希望的是一个群体的改变,而不是一个单元个体都得写一个对应的触发函数,这样很浪费时间,代码也显得很冗余。
首发链接:https://www.imooc.com/article/284842