作者|蔡竹良很多人可能认为设计模式只是在面试中用到,这并不是一个错误。但是如果你面试的时候只是死记硬背八股文,应该在实际工作中使用,却不知道怎么用,那你就是在自欺欺人,你的代码有多好。那么什么时候应该使用设计模式呢?换个角度,你觉得设计模式是怎么出来的?其实大牛们写了很多代码,觉得一些重复性高或者相似的地方可以做到更好的“高”内聚,“低耦合”。他们不断改进,然后总结自己的设计思路,最终得到我们现在的设计模式,本文介绍几种常用的设计模式。1.工厂模式为什么先说工厂模式呢?因为“工厂”的概念在我们的代码中处处体现,所以很多设计模式都离不开它,并根据它演化而来就在上面,所以我们要先了解它。什么是“工厂”?就像我们生活中的工厂一样,就是生产某些“物品”的地方。在Java代码中,我们使用各种对象来做各种事情,而在这个过程中,我们往往不关心创建的过程,只关心它有哪些方法可用,提供了哪些功能,这时候可以使用工厂模式进行解耦——创建的行为放在工厂,用户专注于使用工具pr由工厂生产。工厂模式可以在下面的模板方法、策略模式和适配器模式中看到。我们所说的工厂模式一般有两种:工厂方法abstractfactory(1)工厂方法工厂方法模式是一种创建型设计模式,它提供了在父类中创建对象的方法,让子类决定实例化对象的类型。工厂方法的具体实现思路是:为创建对象A制定一个接口工厂,这个工厂的实现类构建了A的子类,如:A1、A2、A3……这样,分离了A可以实现对象和对象的创建。觉得没味道?下面通过场景对比来说明它的好处。传统方法和使用工厂方法的场景对比:传统上我需要用到某个类,比如A1,我会新建一个A1,然后进行业务操作。有一天产品告诉我这个逻辑需要加一个A2的业务操作逻辑,只好通过条件判断来加逻辑。但是A1和A2在业务抽象上是一致的,只是实现细节不同(比如:比如运输,我用卡车运输是运输,我用火车运输也是运输,也就是说,交通是目的,我的实现方式可以多种多样)。这时候通过if/else或者switch来写就不符合开闭原则了。使用工厂方法写代码我的代码一开始就说是一种交通工具,用这个交通工具来运输(注意这只是交通工具的抽象概念)。这样我就可以按照业务计算的条件(比如:公路/铁路/海运/空运)丢给工厂,工厂会把具体的运输方式还给我(反正子类可以被迫进入父类)。使用工厂方法后,我的业务代码就不用关注具体的运输方式了,再看它是怎么运输的。transport()的代码不会因为后续产品增加更多的运输方式而受到干扰。开闭原则。伪代码如下:..}}publicclassTransport{私有TransportToolFactory工厂;公共交通工具(intway){if(way==0){factory=newTruckTransportToolFactory();}...}publicvoidtransport(){TransportTooltool=factory.createTool();//继续业务处理}}简单说一下“简单工厂”,伪代码如下:publicvoidtransport(){intway=getWay();//不管是从前端计算还是传过来,反正,得到具体的运输方式TransportTooltool=newTransportToolFactory(way).createTool();//继续业务处理}publicTransportToolcreateTool(){if(way==0){//truck}...}但是,简单工厂的缺点很明显:没有单一职责。从上面的例子不难看出,车、船、飞机、大炮都包括在内。如果业务足够复杂,谁来维护这个工厂类?知道!(2)抽象工厂抽象工厂模式是一种创建型设计模式,它可以创建一系列相关的对象,而无需指定它们的具体类。在我看来,JDBC对抽象工厂模式的应用是非常经典的。DB有很多种,但是不同的公司选择的可能不一样,有的是MySQL,有的是Oracle,有的甚至是SQLServer等等。但是对于我们的开发来说,这些都是DB。如果他们的连接、事务提交、事务回滚等细节需要我们注意(不同DB的具体实现会不一样),这显然很麻烦,我们也不关心。我们只想用Connection创建Session,用Session启动一个事务,等等。如果有一个类可以抽取这一系列的公共行为(如连接、事务处理等),我们只需要使用这个抽象类和它提供的方法即可。事实上,JDBC就是这样做的。配置好具体的数据库配置后,我们只需要在代码中使用接口Factory创建连接、会话、启动事务……首先,连接是对象,会话也是对象,依次类推交易。创建这些对象的方法都被抽象成一个工厂,工厂本身只是一个接口定义,这就是所谓的抽象工厂;如果此时我正在使用MySQL,那么刚才列出的对象都是由MySQL定制的一系列相关对象,这叫做“可以创建一系列相关对象”。2.模板方法模式模板方法模式是一种行为设计模式,它在超类中定义了一个算法的框架,允许子类在不修改结构的情况下重写算法的具体步骤。模板方法的核心是抽象行为相同,但实际行为不同。例如:我们的产品经常收集各种数据来分析用户行为。有时他们为了效率会开发一堆电子文档(如CSV、DOC、TXT等,这些文档记录的数据相似,但数据结构一定不同),让开发者开发一个系统功能,可以根据自己的要求导入。根据自己的要求统计这些数据。对于开发来说,代码几乎是一样的,所有的文件都要导入,解析,逻辑计算后入库。但是,我们导入文件后,解析文件代码不同,逻辑计算有时可能不同,但是最后一步出库的概率是一样的。对于这类业务场景,我们可以定义一个类来指定这些流程。上游调用的时候,调用的是我类的子类,子类会根据自己的业务场景重写自己需要的流程节点的逻辑。3、策略模式策略模式是一种行为设计模式,允许你定义一系列算法,并将每个算法放到一个独立的类中,使算法的对象可以相互替换。比如:我们连接了一个审批流组件,我们还需要在后台保留一条审核记录(方便查询和回溯)。现在我们希望我们做的功能更加通用,也就是可以让其他的功能加入到这个审批流程中,比如:功能认证的授权,工作流配置等。那么在审批开始,必须只有审核数据,不能将我们的认证授权或工作流配置生成到对应的表中,只有审批通过后才会生成授权或配置。这时候,问题就来了。工作流组件回调给我们的时候,是不是每次加一个都要复制上一个函数的回调代码,修改审批状态后删代码,再改?这里需要多少冗余代码?即使你修改了审批流的代码,抽成一个方法,你也会发现每一个回调方法都有你的方法。具体伪代码如下:publicclassCallBack{publicvoidcallback1(Paramparam){//查询审批记录有效性//修改审批记录//处理业务逻辑1}publicvoidcallback1(Paramparam){//查询审批记录的合法性//修改审批记录//处理业务逻辑2}...}我们可以使用策略模式来优化这个场景,我们将业务逻辑处理为算法对象并提取出来,以及不同业务场景的回调业务处理器实现了这个抽象接口,自动为对应的处理器分配策略。伪代码如下:publicclassCallBack{privateStrategystrategy=newStrategy();publicvoidcallback(Paramparam){//查询审批记录有效性//修改审批记录//处理业务逻辑strategy.getHandle(param.getServiceName()).invokeHandle();}}publicclassStrategy{privateMap 截至SpringFramework4.2,此接口取代了基于类的*{@linkSmartApplicationListener},完全处理通用事件类型。**@authorStephaneNicoll*@since4.2*@seeSmartApplicationListener*@seeGenericApplicationListenerAdapter*/publicinterfaceGenericApplicationListenerextends
