前言
为了便于各位看后面例子的时候容易理解,博主这里先给出引自其它地方的简单工厂模式的定义。定义:从设计模式的类型上来说,简单工厂模式是属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。
定义中最重要的一句话就是,由一个工厂对象决定创建出哪一种产品类的实例,这个博主在下面会专门举一个现实应用中的例子去展现。
栗子
这里给出简单工厂模式的类图,图片源于百度百科如下:下面博主将上面的类图转化为更为简单的JAVA代码,便于清晰的展示上面类图中各个类之间的关系。
首先是产品接口:
1 | public interface IProduct { |
1 | // 产品A |
1 | // 产品B |
1 | public class Creator { |
1 | public class Client { |
结果:
1 | 产品A方法! |
下面博主就找一个各位基本上都使用过或者将来要使用的一个例子来说明简单工厂模式,我们去模拟一个简单的struts2的功能。
博主会自己制作一个简单的WEB项目来做例子,其中会忽略掉很多细节,目的是为了突出我们的简单工厂模式。
众所周知,我们平时开发web项目大部分是以spring作为平台,来集成各个组件,比如集成struts2来完成业务层与表现层的逻辑,集成hibernate或者ibatis来完成持久层的逻辑。
struts2在这个过程当中提供了分离数据持久层,业务逻辑层以及表现层的责任,有了Struts2,我们不再需要servlet,而是可以将一个普通的Action类作为处理业务逻辑的单元,然后将表现层交给特定的视图去处理,比如JSP,template等等。
我们来尝试着写一个非常非常简单的web项目,来看看在最原始的时候,也就是没有spring,struts2等等这些个开源框架的时候,我们都是怎么过的。
由于博主会省略WEB架构过程当中的很多细节,所以最好是各位亲手做过一些项目,相对而言看起来会更有体会一些,不过博主相信既然有兴趣来看设计模式,应该都基本上有过这种锻炼。
下面博主把我们一个简单的WEB项目中需要的类都列出来,并加上简单的注释。
1 | import javax.servlet.http.HttpServlet; |
但是这样我们有很多限制,比如我们一个servlet一般只能负责一个单一的业务逻辑,因为我们所有的业务逻辑通常情况下都集中在doPost这样一个方法当中,可以想象下随着业务的增加,我们的servlet数量会高速增加,这样不仅项目的类会继续增加,最最恶心的是,我们每添加一个servlet就要在web.xml里面写一个servlet配置。
但是如果我们让一个Servlet负责多种业务逻辑的话,那我们需要在doPost方法中加入很多if判断,去判断当前的操作。
比如我们将上述三个servlet合一的话,你会在doPost出现以下代码:
1 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { |
1 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { |
虽然我们已经将各个单一的业务逻辑拆分成方法,但这依然是违背单一原则这个小萝莉的,因为我们的servlet应该只是处理业务逻辑,而不应该还要负责与业务逻辑不相关的处理方法定位这样的责任,这个责任应该交给请求方,原本在三个servlet分别处理登陆,注销和注册的时候,其实就是这样的,作为请求方,只要是请求LoginServlet,就说明请求的人是要登陆,处理这个请求的servlet不需要再出现有关判断请求操作的代码。
所以我们需要想办法把判断的业务逻辑交给请求方去处理,回想下struts2的做法,我们可以简单模拟下struts2的做法。相信不少同学应该都用过struts2,那么你肯定对以下配置很熟悉。if和switch)
1 | <filter> |
我们来模拟一个分配请求的过滤器,它的任务就是根据用户的请求去产生响应的servlet处理请求,而这些servlet其实就是上面的例子当中的productA和productB这类的角色,也就是具体的产品,而它们实现的接口正是Servlet这个抽象的产品接口。
我们用这个过滤器来消除servlet在web.xml的配置,帮我们加快开发的速度,我们写出如下filter:
1 | package com.web.filter; |
1 | <filter> |
下面给出我们的主角,我们的servlet工厂,它就相当于上面的Creator:
1 | package com.web.factory; |
虽说这些个else if并不是好代码的征兆,不过这个简单工厂最起码帮我们解决了恶心的xml配置,说起来也算功不可没。
现在我们可以请求/contextPath/servlet/login来访问LoginServlet,而不再需要添加web.xml的配置,虽说这么做,我们对修改是开放的,因为每增加一个servlet,我们都需要修改工厂类,去添加一个if判断,但是博主个人还是觉得我宁可写if,也不想去copy那个当初让我痛不欲生的xml标签,虽说我刚才还说让你忘掉elseif,我说过吗?好吧。。我说过,但是这只是我们暂时的做法,我们可以有很多种做法去消除掉这些else if。
简单工厂是设计模式当中相对比较简单的模式,它甚至都没资格进入GOF的二十三种设计模式,所以可见它多么卑微了,但就是这么卑微的一个设计模式,也能真正的帮我们解决实际当中的问题,虽说这种解决一般只能针对规模较小的项目。
写到这里,简单工厂模式当中出现的角色,已经很清晰了。我们上述简单工厂当中设计到的类就是Servlet接口,ServletFactory以及各种具体的LoginServlet,RegisterServlet等等。
总结起来就是一个工厂类,一个产品接口(其实也可以是一个抽象类,甚至一个普通的父类,但通常我们觉得接口是最稳定的,所以基本不需要考虑普通父类的情况),和一群实现了产品接口的具体产品,而这个工厂类,根据传入的参数去创造一个具体的实现类,并向上转型为接口作为结果返回。
我们在这里将上述穿插的简单工厂模式抽离出来,注释中有博主个人的见解,帮助各位理解。
1 | //相当于简单工厂模式中的产品接口 |
为了更加方便各位的对比,博主这里给出上面JAVA代码的类图。
其实我们针对创建Servlet实例这一部分逻辑的控制依旧有很多很多的优化余地,但是限于本章介绍的内容,所以我们就适可而止。
ps:因作者能力有限,有错误的地方请见谅
- 喜欢这篇文章的话可以用快捷键
Ctrl + D
来收藏本页
最后更新: 2018年11月05日 14:38