概述
回想刚开始学习设计模式时,被23种设计模式冲昏头脑,很想学好,但是越看越晕。工作几年后,回头在看,略有些心得,因此做个小总结,也希望能带给后来的小伙伴一点点启发。
一、设计模式之道
很喜欢一些大佬们对知识的分类法,他们会把知识分成“道法术器”(也是源自道家的思想)。所谓“道”,我理解指的就是根源和初心了,它的特点就是高度概括,包罗万象;所谓“法”,我理解就是运行的法度、制度、规章,它的特点就是保证系统的正确运转;所谓“术”,就是一些做事的方法,它的特点就是有条理,有步骤;所谓“器”,则是一些辅助工具了。
我在这里特意提这一点,是因为我们学习任何事物,总脱不开从道开始(自上而下)还是从术开始(自下而上),而在设计模式的学习中,我认为就应该是自上而下的。现在网络上很多文章,上来就是一通介绍,对设计模式一个一个的介绍,有的讲的详细的还会举些“鸭子的类型”、“工厂生产”的例子等等,看的时候热热闹闹地,实际中你回到现实,看着手里项目里面一坨坨几千行代码的类,是不是还是感觉无从下手?我觉得问题就是出在过于强调术了,看介绍很清晰,实际使用就很容易沦为滥用、不敢用、用错了的地步。实际上,整个设计模式的核心,也就是设计模式之道,我认为就是一个字 — “拆”。大道至简,其实不论是分布式系统、分库分表、微服务等等,说到最后就是个“拆”字,无非就是怎么拆,怎么保证拆了以后能维护的问题。那么“拆”背后反映的是什么呢?是实现拆分的要付出工作量,也是系统角色多了以后的复杂性。很多文章介绍了“分布式”、“微服务”、“设计模式”等等概念以及它们的优点,却很少提及它们的缺陷和问题,实际上前人早就总结过:“软件开发没有银弹”,一切事物都是有其优点和缺点的。比如一个运行稳定地老系统,也没什么新需求了,硬要套一些设计模式上去,进行代码的改造,大概率是要出问题的;或者新系统上来就“面向接口”编程,每个类都搞个对应的接口,这开发效率估计也是不能接受。这也就是为什么我要说设计模式的学习不同于一般的学习路径,需要从“道”开始。也就是抓住事物的本源,而不是把设计模式生搬硬套上去。
再谈谈设计模式的“法”,大家也听得多了,就是“七大原则”、“高内聚,低耦合”等,乍一听云里雾里的,其实也就是告诉你怎么拆比较好,因为是前人总结的经验,所以一般按照这个指导来做就没什么问题。比如说哪天你突然搞出一个23种模式之外的新设计模式,“法”可以让你知道这个新开创的模式靠不靠谱,是不是符合规范的。
最后谈谈设计模式的“术”,也就是总结的23种不同的设计模式了,大部分设计模式的关键,不在于类图、示例代码等,而在于它的提出是为了解决什么问题。“术”是很有局限性的,它的出现可能就是为了解决某一个具体问题,我们带着这个问题去看这个设计模式,可能理解起来就相对简单了。
以上这个图就说明了,大部分设计模式,纵向来看,是引入了一个新角色,用来解决某个问题;横向来看,是拆分成类和接口,也就是依赖倒置原则。但是也可以看出,应用设计模式,会导致代码和文件数量激增,甚至有可能降低代码的可读性。
二、工厂模式的理解和感悟
带着以上的思想再来看工厂模式,就会发现三种工厂模式不用记忆,它们只不过是递进关系,因为解决的问题越来越复杂,但是本质的思想是不变的。这里我既不画类图,也不写示例代码,从“问题、解决方法”两层分类来介绍工厂模式。
简单工厂模式
- 问题:需要分离创建代码和类代码
这个场景太常见了,我们想使用某个类,但不想实例化(new)它。可能是实例化太麻烦,也可能是有很多类似的类,想在统一的地方实例化。一般我们比较常用一些依赖注入框架来做,但如果不用框架,我们也可以用工厂模式来实现。 - 解决方法:设计一个工厂类
这个工厂类提供创建代码,它最后可以返回实例化后的产品类,也可以返回产品类对应的接口,返回类还是接口其实都不影响,看你需不需要隐藏类的实现细节,因为这个模式的关键就是工厂这个概念。
工厂方法模式
- 问题:单个工厂不够用
可能你使用以上的模式发现,这个工厂内部生产着十多种不同的类,每修改一种或者增加一种就需要改代码,这时候又需要拿出“拆”字诀。 - 解决方法:为工厂类增加抽象层
定义一个父类或者接口,然后根据不同的产品实现拆分成不同的子工厂,它们同时实现了同一个接口。这样系统内部的类就又多了,但是庞大的单工厂被拆分成多个小工厂,利于维护。
抽象工厂模式
- 问题:我有一系列复杂的类,相互之间还有关联,而且我想用工厂模式
这个问题也是最难的问题,我在这里简单的画个图表达一下。
以日常经常碰到的加密解密为例,假设我写好了四个类,AES256RSA256表示秘钥长度256位,加密算法是AESRSA的加解密专用工具类;AES512RSA512类似,就是长度上升了而已。如图我们分成了两大类,但实际上它们还有一种关联关系,就是秘钥长度的关联关系。现在我想利用工厂模式去创建类,完成先AES加密,再通过RSA签名的需求。
- 解决方法:
- 简单工厂模式行不行?
当然可以,我设计个AES工厂,根据传入的参数key_len
返回是256还是512长度;再设计个RSA工厂,根据传入的参数key_len
返回是256还是512长度。就是用的时候有点繁琐,先初始化AES工厂,再初始化RSA工厂。要是以后来个再用RC4算法加密一遍的需求,还得加个RC4工厂。 - 那工厂方法模式行不行?
当然也可以,但是不解决任何问题,还更加复杂了。 - 抽象工厂模式
再思考一下需求:AES加密 -> RSA签名。最好能通过一个工厂类完成这个需求,那就可以选取秘钥长度这个维度:
如果还需要再用RC4算法加密,直接在Factory中添加·new·方法即可。class 256Factory { newAES() newRSA() } class 512Factory { newAES() newRSA() } func main(){ Factory f = new 256Factory() f.newAES().Encrypt() f.newRSA().Sign() }
所以抽象工厂方法解决的问题一是比较复杂的类,二是类之间相互有关联。但其实本质思想还是简单工厂模式的思想。同时也可以看出,一个问题可以有多个解决方案,最牛逼的方案一定会比较复杂的,但适不适合得看具体情况。
- 简单工厂模式行不行?
感悟
写了这么多,特意没有画类图,就是感觉并不是一定要按照类图或者示例代码来实现,才叫XX模式,否则岂不是落了用“术”的下乘。主要看看提出这个模式是为了解决什么问题,只要能解决问题且不违背软件设计的七大原则即可。除了文中举例的工厂模式,其它的设计模式思想也是大同小异,还是那句话,学习设计模式应该从掌握“道”入手,也不应该学的过早,否则容易为了设计模式而设计模式。
三、推荐阅读
设计模式介绍(我认为讲的最详细的)
最后
以上就是仁爱鸵鸟为你收集整理的对设计模式中工厂模式的理解和感悟的全部内容,希望文章能够帮你解决对设计模式中工厂模式的理解和感悟所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复