首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

容易工厂方法模式

2012-08-22 
简单工厂方法模式1。实现接口编程,隔离实现,不再对外暴露接口的实现,接口的实现转交给工厂方法。?简单工厂??

简单工厂方法模式

1。实现接口编程,隔离实现,不再对外暴露接口的实现,接口的实现转交给工厂方法。

?

简单工厂


??????? 简单工厂不是一个标准的设计模式,但是它实在是太常用了,简单而又神奇,所以还是需要好好掌握的,就当是对学习设计模式的热身运动吧。
??????? 为了保持一致性,我们尽量按照学习其它模式的步骤来进行学习。


1? 场景问题

??????? 大家都知道,在Java应用开发中,要“面向接口编程”。
??????? 那么什么是接口?接口有什么作用?接口如何使用?一起来回顾一下:


1.1? 接口回顾

(1)Java中接口的概念
??????? 在Java中接口是一种特殊的抽象类,跟一般的抽象类相比,接口里面的所有方法都是抽象方法,接口里面的所有属性都是常量。也就是说,接口里面是只有方法定义而不会有任何方法实现。
(2)接口用来干什么
??????? 通常用接口来定义实现类的外观,也就是实现类的行为定义,用来约束实现类的行为。接口就相当于一份契约,根据外部应用需要的功能,约定了实现类应该要实现的功能,但是具体的实现类除了实现接口约定的功能外,还可以根据需要实现一些其它的功能,这是允许的,也就是说实现类的功能包含但不仅限于接口约束的功能。
??????? 通过使用接口,可以实现不相关类的相同行为,而不需考虑这些类之间的层次关系,接口就是实现类对外的外观。
(3)接口的思想
??????? 根据接口的作用和用途,浓缩下来,接口的思想就是“封装隔离”。
??????? 通常提到封装是指对数据的封装,但是这里的封装是指“对被隔离体的行为的封装”,或者是“对被隔离体的职责的封装”;而隔离指的是外部调用和内部实现,外部调用只能通过接口进行调用,而外部调用是不知道内部具体实现的,也就是说外部调用和内部实现是被接口隔离开的。
(4)使用接口的好处
??????? 由于外部调用和内部实现被接口隔离开了,那么只要接口不变,内部实现的变化就不会影响到外部应用,从而使得系统更灵活,具有更好的扩展性和可维护性,这也就是所谓“接口是系统可插拔性的保证”这句话的意思。
(5)接口和抽象类的选择
??????? 既然接口是一种特殊的抽象类,那么在开发中,何时选用接口,何时选用抽象类呢?
??????? 对于它们的选择,在开发中是一个很重要的问题,特别总结两句话给大家:

优先选用接口 在如下情况应选择抽象类:既要定义子类的行为,又要为子类提供公共的功能
1.2? 面向接口编程

??????? 面向接口编程是Java编程中的一个重要原则。
??????? 在Java 程序设计里面,非常讲究层的划分和模块的划分。通常按照三层来划分Java程序,分别是表现层、逻辑层、数据层,它们之间都要通过接口来通讯。
??????? 在每一个层里面,又有很多个小模块,一个小模块对外也应该是一个整体,那么一个模块对外也应该提供接口,其它地方需要使用到这个模块的功能,都应该通过此接口来进行调用。这也就是常说的“接口是被其隔离部分的外观”。基本的三层结构如图1所示:

?
容易工厂方法模式
?图1? 基本的三层结构示意图

在一个层内部的各个模块交互也要通过接口,如图2所示:

?
容易工厂方法模式
?

?图2? 一个层内部的各个模块交互示意图


??????? 各个部分的接口具体应该如何去定义,具体的内容是什么,不去深究,那是需要具体问题具体分析的,这里只是来学习设计的方法。
??????? 上面频频提到“组件”,那么什么是组件呢?先简单的名词解释一下:
??????? 所谓组件:从设计上讲,组件就是能完成一定功能的封装体。小到一个类,大到一个系统,都可以称为组件,因为一个小系统放到更大的系统里面去,也就当个组件而已。事实上,从设计的角度看,系统、子系统、模块、组件等说的其实是同一回事情,都是完成一定功能的封装体,只不过功能多少不同而已。
??????? 继续刚才的思路,大家会发现,不管是一层还是一个模块或者一个组件,都是一个被接口隔离的整体,那么下面我们就不去区分它们,统一认为都是接口隔离体即可,如图3所示:

?
容易工厂方法模式
图3? 接口隔离体示意图


?既然在Java中需要面向接口编程,那么在程序中到底如何使用接口,来做到真正的面向接口编程呢?

?1.3? 不用模式的解决方案

??????? 回忆一下,以前是如何使用接口的呢,假设有一个接口叫Api,然后有一个实现类Impl实现了它,在客户端怎么用这个接口呢?
??????? 通常都是在客户端创建一个Impl的实例,把它赋值给一个Api接口类型的变量,然后客户端就可以通过这个变量来操作接口的功能了,此时具体的结构图如图4:

?

?
容易工厂方法模式
?图4? 基本的接口和实现

还是用代码来说明,会更清楚一些。

(1)先定义接口Api,示例代码如下:


          ?

          2:应用简单工厂来解决的思路
          ??????? 分析上面的问题,虽然不能让模块外部知道模块内的具体实现,但是模块内部是可以知道实现类的,而且创建接口是需要具体实现类的。
          ??????? 那么干脆在模块内部新建一个类,在这个类里面来创建接口,然后把创建好的接口返回给客户端,这样外部应用就只需要根据这个类来获取相应的接口对象,然后就可以操作接口定义的方法了。把这样的对象称为简单工厂,就叫Factory吧。
          ??????? 这样一来,客户端就可以通过这个Factory来获取需要的接口对象,然后调用接口的方法来实现需要的功能,而且客户端也不用再关心具体实现了。


          2.2? 简单工厂结构和说明

          ??????? 简单工厂的结构如图5所示:

          ?
          容易工厂方法模式
          ?Api:
          ??????? 定义客户所需要的功能接口
          Impl:
          ?????? 具体实现Api的实现类,可能会有多个
          Factory:
          ?????? 工厂,选择合适的实现类来创建Api接口对象
          Client:
          ?????? 客户端,通过Factory去获取Api接口对象,然后面向Api接口编程


          2.3? 简单工厂示例代码

          (1)先看看Api的定义,示例代码如下:

                    ????????????????????? 图6? 使用简单工厂重写示例的结构示意图

                    ?(1)接口Api和实现类Impl都和前面的示例一样,就不去赘述了。
                    (2)新创建一个简单工厂的对象,示例代码如下:


                        ?图8? 简单工厂的调用顺序示意图


                        (6)简单工厂命名的建议

                        ?

                        类名建议为“模块名称+Factory”,比如:用户模块的工厂就称为:UserFactory 方法名称通常为“get+接口名称”或者是“create+接口名称”,比如:有一个接口名称为UserEbi,那么方法名称通常为:getUserEbi 或者是 createUserEbi。 ?当然,也有一些朋友习惯于把方法名称命名为“new+接口名称”,比如:newUserEbi,我们不是很建议。因为new在Java中代表特定的含义,而且通过简单工厂的方法来获取对象实例,并不一定每次都是要new一个新的实例。如果使用newUserEbi,这会给人错觉,好像每次都是new一个新的实例一样。

                        ?

                        3.3? 简单工厂中方法的写法

                        ?

                        ??????? 虽然说简单工厂的方法多是用来造接口的,但是仔细分析就会发现,真正能实现功能的是具体的实现类,这些实现类是已经做好的,并不是真的靠简单工厂来创造出来的,简单工厂的方法无外乎就是:实现了选择一个合适的实现类来使用。
                        ??????? 所以简单工厂方法的内部主要实现的功能是“选择合适的实现类”来创建实例对象。既然要实现选择,那么就需要选择的条件或者是选择的参数,选择条件或者是参数的来源通常又有几种:

                        来源于客户端,由Client来传入参数 来源于配置文件,从配置文件获取用于判断的值 来源于程序运行期的某个值,比如从缓存中获取某个运行期的值

                        ???????? 下面来看个示例,看看由客户端来传入参数,如何写简单工厂中的方法。
                        (1)在刚才的示例上再添加一个实现,称为Impl2,示例代码如下:

                                      public class Client {public static void main(String[] args) {Api api = Factory.createApi();api.test1("哈哈,不要紧张,只是个测试而已!");}}

                                      ?把上面的示例代码敲到电脑里面,测试一下,体会体会。


                                      3.5? 简单工厂的优缺点帮助封装
                                      ??? 简单工厂虽然很简单,但是非常友好的帮助我们实现了组件的封装,然后让组件外部能真正面向接口编程。 解耦
                                      ??? 通过简单工厂,实现了客户端和具体实现类的解耦。
                                      ??? 如同上面的例子,客户端根本就不知道具体是由谁来实现,也不知道具体是如何实现的,客户端只是通过工厂获取它需要的接口对象。 可能增加客户端的复杂度
                                      ??? 如果通过客户端的参数来选择具体的实现类,那么就必须让客户端能理解各个参数所代表的具体功能和含义,这会增加客户端使用的难度,也部分暴露了内部实现,这种情况可以选用可配置的方式来实现。 不方便扩展子工厂
                                      ??? 私有化简单工厂的构造方法,使用静态方法来创建接口,也就不能通过写简单工厂类的子类来改变创建接口的方法的行为了。不过,通常情况下是不需要为简单工厂创建子类的。

                                      ?


                                      3.6? 思考简单工厂

                                      1:简单工厂的本质
                                      ??????? 简单工厂的本质是:选择实现
                                      ??????? 注意简单工厂的重点在选择,实现是已经做好了的。就算实现再简单,也要由具体的实现类来实现,而不是在简单工厂里面来实现。简单工厂的目的在

热点排行