研磨设计模式之简单工厂模式-3
??????? 首先来解决一个常见的疑问:可能有朋友会认为,上面示例中的简单工厂看起来不就是把客户端里面的“new Impl()”移动到简单工厂里面吗?不还是一样通过new一个实现类来得到接口吗?把“new Impl()”这句话放到客户端和放到简单工厂里面有什么不同吗?
??????? 理解这个问题的重点就在于理解简单工厂所处的位置。
??????? 根据前面的学习,我们知道接口是用来封装隔离具体的实现的,目标就是不要让客户端知道封装体内部的具体实现。简单工厂的位置是位于封装体内的,也就是简单工厂是跟接口和具体的实现在一起的,算是封装体内部的一个类,所以简单工厂知道具体的实现类是没有关系的。整理一下简单工厂的结构图,新的图如图7所示:
??????????????????????????????????????? 图7? 整理后的简单工厂结构
???????
??????? 图7中虚线框,就好比是一个组件的包装边界,表示接口、实现类和工厂类组合成了一个组件,在这个封装体里面,只有接口和工厂是对外的,也就是让外部知道并使用的,所以故意漏了一些在虚线框外,而具体的实现类是不对外的,被完全包含在虚线框内。
??????? 对于客户端而言,只是知道了接口Api和简单工厂Factory,通过Factory就可以获得Api了,这样就达到了让Client在不知道具体实现类的情况下获取接口Api。
??????? 所以看似简单的把“new Impl()”这句话从客户端里面移动到了简单工厂里面,其实是有了质的变化的。
(1)简单工厂的功能
??????? 工厂嘛,就是用来造东西的。在Java里面,通常情况下是用来造接口的,但是也可以造抽象类,甚至是一个具体的类实例。
???????? 一定要注意,虽然前面的示例是利用简单工厂来创建的接口,但是也是可以用简单工厂来创建抽象类或者是普通类的实例的。
(2)静态工厂
??????? 使用简单工厂的时候,通常不用创建简单工厂类的类实例,没有创建实例的必要。因此可以把简单工厂类实现成一个工具类,直接使用静态方法就可以了,也就是说简单工厂的方法通常都是静态的,所以也被称为静态工厂。如果要防止客户端无谓的创造简单工厂实例,还可以把简单工厂的构造方法私有化了。
(3)万能工厂
??????? 一个简单工厂可以包含很多用来构造东西的方法,这些方法可以创造不同的接口、抽象类或者是类实例,一个简单工厂理论上可以构造任何东西,所以又称之为“万能工厂”。
?????? 虽然上面的实例中,在简单工厂里面只有一个方法,但事实上,是可以有很多这样创建方法的,这点要注意。
(4)简单工厂创建对象的范围
?????? 虽然从理论上讲,简单工厂什么都能造,但对于简单工厂可创建对象的范围,通常不要太大,建议控制在一个独立的组件级别或者一个模块级别,也就是一个组件或模块一个简单工厂。否则这个简单工厂类会职责不明,有点大杂烩的感觉。
(5)简单工厂的调用顺序示意图
?????? 简单工厂的调用顺序如图8所示:
?图8? 简单工厂的调用顺序示意图
(6)简单工厂命名的建议
?
类名建议为“模块名称+Factory”,比如:用户模块的工厂就称为:UserFactory方法名称通常为“get+接口名称”或者是“create+接口名称”,比如:有一个接口名称为UserEbi,那么方法名称通常为:getUserEbi 或者是 createUserEbi。?当然,也有一些朋友习惯于把方法名称命名为“new+接口名称”,比如:newUserEbi,我们不是很建议。因为new在Java中代表特定的含义,而且通过简单工厂的方法来获取对象实例,并不一定每次都是要new一个新的实例。如果使用newUserEbi,这会给人错觉,好像每次都是new一个新的实例一样。?
3.3? 简单工厂中方法的写法?
??????? 虽然说简单工厂的方法多是用来造接口的,但是仔细分析就会发现,真正能实现功能的是具体的实现类,这些实现类是已经做好的,并不是真的靠简单工厂来创造出来的,简单工厂的方法无外乎就是:实现了选择一个合适的实现类来使用。
??????? 所以简单工厂方法的内部主要实现的功能是“选择合适的实现类”来创建实例对象。既然要实现选择,那么就需要选择的条件或者是选择的参数,选择条件或者是参数的来源通常又有几种:
???????? 下面来看个示例,看看由客户端来传入参数,如何写简单工厂中的方法。
(1)在刚才的示例上再添加一个实现,称为Impl2,示例代码如下: