2.工厂方法(FactoryMethod)
1)场景问题
用户向工厂下手机订单,工厂能生产Phone5S和Phone6E两种型号的手机。
工厂要生产满足用户需求的手机,有足够的资源材料,但是流水线上的操作人员并不知道用户究竟要使用哪一种版本型号。
2)问题描述
实现一个功能对象,需要创建功能接口的具体实例对象,但是只知道有这个接口,不知道其具体的实现
3)解决方案
模式定义:
定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到其子类。 |
模式结构:
Product:定义工厂方法所创建的对象的接口,也就是实际需要使用的对象的接口。 ConcreteProduct:具体的Product接口的实现对象。 Creator:创建器,声明工厂方法,工厂方法通常会返回一个Product类型的实例对象,而且多是抽象方法。也可以在Creator里面提供工厂方法的默认实现,让工厂方法返回一个缺省的Product类型的实例对象。 ConcreteCreator:具体的创建器对象,覆盖实现Creator定义的工厂方法,返回具体的Product实例。 |
4)示例代码
(1)Product定义的示例代码如下:
/** * 工厂方法所创建的对象的接口 */ publicinterfaceProduct{ //可以定义Product的属性和方法 } |
(2)Product实现对象的示例代码如下:
/** * 具体的Product对象 */ publicclassConcreteProductimplementsProduct{ //实现Product要求的方法 } |
(3)创建器定义的示例代码如下:
/** * 创建器,声明工厂方法 */ publicabstractclassCreator{ /** * 创建Product的工厂方法 * @return Product对象 */ protectedabstractProductfactoryMethod(); /** * 示意方法,实现某些功能的方法 */ publicvoidsomeOperation(){ // 通常在这些方法实现中需要调用工厂方法来获取Product对象 Product Product =factoryMethod(); } } |
(4)创建器实现对象的示例代码如下:
/** * 具体的创建器实现对象 */ publicclassConcreteCreatorextendsCreator{ protectedProductfactoryMethod(){ // 重定义工厂方法,返回一个具体的Product对象 returnnewConcreteProduct(); } } |
5)优缺评价
优点 ·可以在不知具体实现的情况下编程 选择具体实现的任务延迟到子类完成 ·更容易扩展对象的新版本 只要新加入一个子类来提供新的工厂方法实现,然后在客户端使用这个新的子类即可。 ·连接平行的类层次 |
缺点 ·具体产品对象和工厂方法的耦合性 工厂方法模式中,工厂方法是需要创建产品对象的,也就是需要选择具体的产品对象并创建实例,因此具体产品对象和工厂方法是耦合的 |
6)适用场合
使用工厂方法实现示例:
先来按照工厂方法模式的结构,对应出哪些是被创建的Product,哪些是Creator。分析要求实现的功能,要生产的手机型号接口就相当于是Product,而用来实现生产手机的业务功能对象就相当于Creator。把Product和Creator分开后,就可以分别来实现它们了。
/** * 生产的手机对象的接口 */ publicinterfacePhoneApi{ publicbooleanproduct(String type); } |
/** * 生产IPhone5s的手机 */ publicclassPhone5SimplementsPhoneApi{ publicbooleanproduct(String type){ //选择生产IPhone5s的手机 System.out.println("生产了型号为"+ type +"的Phone5S手机"); returntrue; } } |
/** * 生产IPhone6e的手机 */ publicclassPhone6EimplementsPhoneApi{ publicbooleanproduct(String type){ //选择生产IPhone6e的手机 System.out.println("生产了型号为"+ type +"的Phone6E手机"); returntrue; } } |
实现生产操作的代码如下:
** * 实现生产手机的业务功能对象 */ publicabstractclassProductOperate{ /** * 生产手机 * @param type 需要生产的型号 * @return是否成功生产 */ publicbooleanproduct(String type){ //使用工厂方法 PhoneApi api =factoryMethod(); return api.product(type); } /** * 工厂方法,创建生产的手机对象的接口对象 * @return生产的手机对象的接口对象 */ protectedabstractPhoneApifactoryMethod(); } |
加入两个具体Creator实现:
实现生产Phone5S型号手机的代码如下:
/** * 具体的手机生产对象,实现生产Phone5S的对象 */ publicclassProductPhone5SOperateextendsProductOperate{ protectedPhoneApifactoryMethod(){ //创建生产Phone5S的手机类型的对象 returnnewPhone5S(); } } |
实现生产Phone6E型号手机的代码如下:
/** * 具体的手机生产对象,实现生产Phone6E的对象 */ publicclassProductPhone6EOperateextendsProductOperate{ protectedPhoneApifactoryMethod(){ //创建生产Phone5S的手机类型的对象 returnnewPhone6E(); } } |
最后,客户端直接创建需要使用的Creator对象,然后调用相应的功能方法,示例代码如下:
publicclassClient{ publicstaticvoidmain(String[] args){ //创建需要使用的Creator对象 ProductOperate operate =newProductPhone6EOperate(); //调用显示生产内容的功能方法 operate.product("Phone6E001"); } } |
运行结果如下:
还可以修改客户端new的对象,切换成其他对象。
7)相关延伸
依赖注入/控制反转;
工厂方法模式和IOC/DI的思想很类似
A1里面要使用C1对象,不是由A1主动去获取C1对象,
而是创建一个工厂方法,类似于一个注入的途径;
然后由子类,假设叫A2,由A2来获取C1对象,
在调用的时候替换掉A1的相应方法,
相当于反向注入回到A1里面。
示例代码如下:
publicabstractclassA1{ /** * 工厂方法,创建C1,类似于从子类注入进来的途径 * * @return C1的对象实例 */ protectedabstractC1createC1();
publicvoidt1(){ // 这里需要使用C1类,可是不知道究竟是用哪一个 // 也就不主动去创建C1了,怎么办? // 反正会在子类里面实现们这里不用管怎么获取C1,直接使用就好了 createC1().tc(); } } |
子类代码如下
publicclass A2 extends A1 { protected C1 createC1(){ //真正的选择具体实现,并创建对象 return new C2(); } } |