研磨设计模式之工厂方法方式-3
3 模式讲解
3.1 认识工厂方法模式
(1)模式的功能
工厂方法的主要功能是让父类在不知道具体实现的情况下,完成自身的功能调用,而具体的实现延迟到子类来实现。
这样在设计的时候,不用去考虑具体的实现,需要某个对象,把它通过工厂方法返回就好了,在使用这些对象实现功能的时候还是通过接口来操作,这非常类似于IoC/DI的思想,这个在后面给大家稍详细点介绍一下。
(2)实现成抽象类
工厂方法的实现中,通常父类会是一个抽象类,里面包含创建所需对象的抽象方法,这些抽象方法就是工厂方法。
这里要注意一个问题,子类在实现这些抽象方法的时候,通常并不是真的由子类来实现具体的功能,而是在子类的方法里面做选择,选择具体的产品实现对象。
父类里面,通常会有使用这些产品对象来实现一定的功能的方法,而且这些方法所实现的功能通常都是公共的功能,不管子类选择了何种具体的产品实现,这些方法的功能总是能正确执行。
(3)实现成具体的类
当然也可以把父类实现成为一个具体的类,这种情况下,通常是在父类中提供获取所需对象的默认实现方法,这样就算没有具体的子类,也能够运行。
通常这种情况还是需要具体的子类来决定具体要如何创建父类所需要的对象。也把这种情况称为工厂方法为子类提供了挂钩,通过工厂方法,可以让子类对象来覆盖父类的实现,从而提供更好的灵活性。
(4)工厂方法的参数和返回
工厂方法的实现中,可能需要参数,以便决定到底选用哪一种具体的实现。也就是说通过在抽象方法里面传递参数,在子类实现的时候根据参数进行选择,看看究竟应该创建哪一个具体的实现对象。
一般工厂方法返回的是被创建对象的接口对象,当然也可以是抽象类或者一个具体的类的实例。
(5)谁来使用工厂方法创建的对象
这里首先要搞明白一件事情,就是谁在使用工厂方法创建的对象?
事实上,在工厂方法模式里面,应该是Creator中的其它方法在使用工厂方法创建的对象,虽然也可以把工厂方法创建的对象直接提供给Creator外部使用,但工厂方法模式的本意,是由Creator对象内部的方法来使用工厂方法创建的对象,也就是说,工厂方法一般不提供给Creator外部使用。
客户端应该是使用Creator对象,或者是使用由Creator创建出来的对象。对于客户端使用Creator对象,这个时候工厂方法创建的对象,是Creator中的某些方法使用。对于使用那些由Creator创建出来的对象,这个时候工厂方法创建的对象,是构成客户端需要的对象的一部分。分别举例来说明。
①客户端使用Creator对象的情况
比如前面的示例,对于“实现导出数据的业务功能对象”的类ExportOperate,它有一个export的方法,在这个方法里面,需要使用具体的“导出的文件对象的接口对象” ExportFileApi,而ExportOperate是不知道具体的ExportFileApi实现的,那么怎么做的呢?就是定义了一个工厂方法,用来返回ExportFileApi的对象,然后export方法会使用这个工厂方法来获取它所需要的对象,然后执行功能。
这个时候的客户端是怎么做的呢?这个时候客户端主要就是使用这个ExportOperate的实例来完成它想要完成的功能,也就是客户端使用Creator对象的情况,简单描述这种情况下的代码结构如下:
/** * 客户端使用Creator对象的情况下,Creator的基本实现结构 */ public abstract class Creator { /** * 工厂方法,一般不对外 * @return 创建的产品对象 */ protected abstract Product factoryMethod(); /** * 提供给外部使用的方法, * 客户端一般使用Creator提供的这些方法来完成所需要的功能 */ public void someOperation(){ //在这里使用工厂方法 Product p = factoryMethod(); } } |
②客户端使用由Creator创建出来的对象
另外一种是由Creator向客户端返回由“工厂方法创建的对象”来构建的对象,这个时候工厂方法创建的对象,是构成客户端需要的对象的一部分。简单描述这种情况下的代码结构如下:
/** * 客户端使用Creator来创建客户端需要的对象的情况下,Creator的基本实现结构 */ public abstract class Creator { /** * 工厂方法,一般不对外,创建一个部件对象 * @return 创建的产品对象,一般是另一个产品对象的部件 */ protected abstract Product1 factoryMethod1(); /** * 工厂方法,一般不对外,创建一个部件对象 * @return 创建的产品对象,一般是另一个产品对象的部件 */ protected abstract Product2 factoryMethod2(); /** * 创建客户端需要的对象,客户端主要使用产品对象来完成所需要的功能 * @return 客户端需要的对象 */ public Product createProduct(){ //在这里使用工厂方法,得到客户端所需对象的部件对象 Product1 p1 = factoryMethod1(); Product2 p2 = factoryMethod2();
//工厂方法创建的对象是创建客户端对象所需要的 Product p = new ConcreteProduct(); p.setProduct1(p1); p.setProduct2(p2);
return p; } } |
小结一下:在工厂方法模式里面,客户端要么使用Creator对象,要么使用Creator创建的对象,一般客户端不直接使用工厂方法。当然也可以直接把工厂方法暴露给客户端操作,但是一般不这么做。
(6)工厂方法模式的调用顺序示意图
由于客户端使用Creator对象有两种典型的情况,因此调用的顺序示意图也分做两种情况,先看看客户端使用由Creator创建出来的对象情况的调用顺序示意图,如图.5所示:
图5 客户端使用由Creator创建出来的对象的调用顺序示意图
接下来看看客户端使用Creator对象时候的调用顺序示意图,如图6所示:
图6 客户端使用Creator对象的调用顺序示意图
未完待续......
尤其是第5点"谁来使用工厂方法创建的对象",以前都没有思考过.
PS:这是我看过的,对工厂方法模式分析得最到位的文章了
小弟对楼主以上的说法有点不太明白,这个product只有一个export()的方法 ,如果这个
产品有多个功能的话 那是岂不是要在creator中封装多个方法去实现product的方法。这样就不成了代理模式了吗, product和product的多个实现类是被代理对象, creator和creator的多个实现类是代理对象,我们new出来的也是createor的实现类,但是在通过代理对象调用product中方法 感觉这个工厂模式的实现目的更是着重强调代理模式功能
小弟才疏学浅,提出的这个观点是不是可笑
对于“在工厂方法模式里面,客户端要么使用Creator对象”这句话的意思,简单点说就是客户端需要的功能,直接由Creator对象来提供了,这个时候工厂方法所创建的对象,是由Creator里面的方法来使用,不是由客户来使用。
对于“要么使用Creator创建的对象”这句话的意思,简单点说,客户端需要的对象,是由Creator来创建的,可以是Product对象,也可以不是,如果不是Product对象,那么Creator对象创建的Product对象,就做为组成客户端需要的对象的一部分了。
这里说的都是对象的问题,跟具体的方法无关,跟Product对象的方法也无关。
不知道是否清楚。