本文来自李明子csdn博客(http://blog.csdn.net/free1985),商业转载请联系博主获得授权,非商业转载请注明出处!
摘要:本文讲解了工厂方法(Factory Method)设计模式的使用目的、基本形态及各参与者,并结合示例代码,讲解了该设计模式在具体业务场景下的使用。

1 目的

工厂方法(Factory Method)提供了创建对象的方法,使对象的实例化延迟至子类。

2 基本形态

工厂方法的基本形态如类图2-1所示。


图2-1 工厂方法类图

3 参与者

结合图2-1,下面介绍各类在工厂方法设计模式中扮演的角色。
3.1 Product
Product是产品父类。虽然它可以是抽象类,也可以是接口,但一般情况下,它是包含各方法默认实现的普通类。
3.2 ConcreteProduct1
ConcreteProduct1是具体产品类。ConcreteProduct1类派生自Product类,可以重写Product中各方法,也可以对Product进行扩展。
3.3 Creator
Creator是创建者父类。它包含创建Product对象的工厂方法FactoryMethod。一般来说,Creator提供了工厂方法FactoryMethod的默认实现,创建Product的实例。另外,Creator也提供了一系列对Product操作的方法,这些方法大多数对Product及其子类是通用的,即不会在ConcreteCreator中被重写。
3.4 ConcreteCreator
ConcreteCreator派生自Creator,是具体产品ConcreteProduct1的创建者。该类重写了工厂方法FactoryMethod,创建ConcreteProduct1对象。另外,根据实际情况,ConcreteCreator也可能重写Creator的部分方法,以实现对ConcreteProduct1的个性化操作。
3.5 Client
Client是工厂方法设计模式的使用者,在上面的类图中并未体现。虽然实例化的具体产品类型对Client是透明的,但Client是知道产品的创建者所属的具体类并负责实例化该类的。

4 代码实践

下面我们用一个业务场景实例来进一步讲解工厂方法的使用。
4.1 场景介绍
某电商平台将用户分为普通用户和VIP用户,不同种类的用户享受的折扣率不同,显示的用户信息栏目也不同。用户信息查看器用于输出用户的信息。
以下各节将介绍该场景各类的具体实现及其在工厂方法设计模式中所对应的参与者角色。
4.2 UserInfo
UserInfo是用户信息类,声明了用户名、用户生日、用户享受的折扣率等用户信息,并提供了用户信息对象的序列化方法。对应于工厂方法模式的参与者,UserInfo是我们的产品父类。下面的代码给出了UserInfo的声明。

package demo.designpattern.factorymethod;
import java.util.Date;/*** 用户信息* Created by LiMingzi on 2017/5/9.*/
public class UserInfo {/*** 用户名*/public String name;/*** 生日*/public Date birthday;/*** 折扣率*/public float discountRate = 0;/*** 构造方法* @param name 用户名* @param birthday 生日*/public UserInfo(String name, Date birthday) {this.name = name;this.birthday = birthday;}/*** 序列化** @return 用户信息*/@Overridepublic String toString() {return "用户名:" + name + "\n生日:" + birthday.toString() + "\n今日折扣率:" + discountRate*100 + "%\n";}
}

4.3 VipUserInfo
VipUserInfo是VIP用户信息类,派生自UserInfo类。除了用户名、用户生日、用户享受的折扣率外,还声明了用户VIP等级等信息,同时重写了用户序列化方法。对应于工厂方法模式的参与者,VipUserInfo是我们的具体产品类。下面的代码给出了VipUserInfo的声明。

package demo.designpattern.factorymethod;import java.util.Date;/*** vip用户信息* Created by LiMingzi on 2017/5/9.*/
public class VipUserInfo extends UserInfo {/*** vip等级*/public int level;/*** 构造方法** @param name     用户名* @param birthday 生日* @param level vip等级*/public VipUserInfo(String name, Date birthday, int level) {super(name, birthday);this.level = level;}/*** 构造方法* @param userInfo 用户信息* @param level vip等级*/public VipUserInfo(UserInfo userInfo,int level){super(userInfo.name, userInfo.birthday);this.level = level;}/*** 序列化** @return 用户信息*/@Overridepublic String toString() {return super.toString()+"VIP等级:" + level + "\n";}
}

4.4 UserMgmt
UserMgmt类是用户管理类,主要声明了创建用户信息对象的方法createUserInfo和输出用户信息的方法outputUserInfo。对应于工厂方法模式的参与者,UserMgmt是我们的创建者父类,createUserInfo是工厂方法。下面的代码给出了UserMgmt的声明。

package demo.designpattern.factorymethod;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;/*** 用户管理类* Created by LiMingzi on 2017/5/9.*/
public class UserMgmt {/*** 输出用户信息* @param userId 用户id*/public void outputUserInfo(String userId){// 用户信息UserInfo userInfo = createUserInfo(userId);System.out.println("用户信息:");System.out.println(userInfo.toString());System.out.println("------------------------------------------------------------------");}/*** 创建用户信息对象* @param userId  用户id* @return 用户信息对象*/protected UserInfo createUserInfo(String userId){// 用户基本信息Object[] userBaseInfo = getUserBaseInfo(userId);// 用户信息UserInfo userInfo = new UserInfo((String) userBaseInfo[0],(Date) userBaseInfo[1]);// 今日日期Calendar today = Calendar.getInstance();today.setTime(new Date());// 会员日全场8折if(28 == today.get(Calendar.DAY_OF_MONTH)){userInfo.discountRate = 0.2f;}else{userInfo.discountRate = 0.0f;}return userInfo;}/*** 获取用户信息(demo)* @param userId 用户id* @return 用户信息,item[0]为用户名,item[1]为用户生日*/private Object[] getUserBaseInfo(String userId){// 用户信息Object[] userBaseInfo = new Object[2];if("001".equals(userId)){userBaseInfo[0] = "张三";userBaseInfo[1] = new Date(new GregorianCalendar(1985,10,12).getTimeInMillis());}else if("002".equals(userId)){userBaseInfo[0] = "李四";userBaseInfo[1] = new Date(new GregorianCalendar(1992,5,14).getTimeInMillis());}return userBaseInfo;}}

上述代码中展示了工厂方法经常被使用的一种模式——隐含调用。即工厂方法createUserInfo并没有被Client直接调用生成对象,而是在公共方法outputUserInfo的实现中间接调用createUserInfo生成具体产品。

4.5 VipUserMgmt
VipUserMgmt是VIP用户管理类,派生自UserMgmt。对应于工厂方法模式的参与者,VipUserMgmt是我们的具体创建者。重写的工厂方法createUserInfo返回具体产品VipUserInfo的对象。下面的代码给出了VipUserMgmt的声明。

package demo.designpattern.factorymethod;/*** vip用户管理类* Created by LiMingzi on 2017/5/9.*/
public class VipUserMgmt extends UserMgmt{/*** 创建用户信息对象* @param userId  用户id* @return 用户信息对象*/protected VipUserInfo createUserInfo(String userId){// 用户信息UserInfo userInfo = super.createUserInfo(userId);// 用户vip等级int level = getUserLevel(userId);// vip用户信息VipUserInfo vipUserInfo = new VipUserInfo(userInfo,level);// vip会员全场九折if(vipUserInfo.discountRate<0.1f){vipUserInfo.discountRate = 0.1f;}return vipUserInfo;}/*** 获取用户等级(此处为demo)* @param id 用户id* @return 用户vip等级*/private int getUserLevel(String id){if("002".equals(id)){return 3;}else {return 1;}}
}

上面代码第13行重写的工厂方法首先调用父类的工厂方法创建父产品对象,再用父产品对象与附加信息进一步创建具体产品对象。这是工厂方法的典型用法,同时应该注意具体产品应包含使用产品父类实例作为参数的构造方法以实现更好的封装性。

4.6 UserInfoViewer
UserInfoViewer实现了用户信息的查看功能,对应于工厂方法模式的参与者,UserInfoViewer是Client。下面的代码给出了UserInfoViewer的声明。

package demo.designpattern.factorymethod;/*** 用户信息查看器* Created by LiMingzi on 2017/5/9.*/
public class UserInfoViewer {/*** 是否为vip用户(demo)* @param userId 用户id* @return 是否为vip用户*/private boolean isVip(String userId){if("002".equals(userId)){return true;}else{return false;}}/*** 查看用户信息* @param userId 用户id*/public void viewUserInfo(String userId){// 用户管理器UserMgmt userMgmt;if(isVip(userId)){userMgmt = new VipUserMgmt();}else {userMgmt = new UserMgmt();}userMgmt.outputUserInfo(userId);}
}

从上述代码中可以看到,UserInfoViewer是知道应该用哪个类对象来实例化UserMgmt的。
4.7 测试代码
为了测试本文中的代码,我们可以编写如下测试代码。

    /*** 工厂方法测试*/public static void factoryMethodTest(){// 用户信息查看器demo.designpattern.factorymethod.UserInfoViewer userInfoViewer = new demo.designpattern.factorymethod.UserInfoViewer();userInfoViewer.viewUserInfo("001");userInfoViewer.viewUserInfo("002");}

编译运行后,得到如下测试结果:

用户信息:
用户名:张三
生日:Tue Nov 12 00:00:00 CST 1985
今日折扣率:0.0%


用户信息:
用户名:李四
生日:Sun Jun 14 00:00:00 CST 1992
今日折扣率:10.0%
VIP等级:3


设计模式讲解与代码实践(三)——工厂方法相关推荐

  1. 设计模式讲解与代码实践(二十三)——模板方法

    本文来自李明子csdn博客(http://blog.csdn.net/free1985),商业转载请联系博主获得授权,非商业转载请注明出处! 1 目的 模板方法(Template Method)模式将 ...

  2. 设计模式学习笔记-2 创建者模式-工厂方法模式

    设计模式学习笔记-2 创建者模式-工厂方法模式 工厂模式介绍 工厂模式又称工厂方法模式,是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型. 这种设计模式使Java开 ...

  3. [Python设计模式] 第8章 学习雷锋好榜样——工厂方法模式

    github地址:https://github.com/cheesezh/python_design_patterns 简单工厂模式 v.s. 工厂方法模式 以简单计算器为例,对比一下简单工厂模式和工 ...

  4. Eclipse远程调试Java代码的三种方法

    Eclipse远程调试Java代码的三种方法, 第1种方法是用来调试已经启动的Java程序,Eclipse可以随时连接到远程Java程序进行调试, 第2种方法可以调试Java程序启动过程,但是Ecli ...

  5. eclipse 远程调试java_Eclipse远程调试Java代码的三种方法

    Eclipse远程调试Java代码的三种方法, 第1种方法是用来调试已经启动的Java程序,Eclipse可以随时连接到远程Java程序进行调试, 第2种方法可以调试Java程序启动过程,但是Ecli ...

  6. 【地铁上的设计模式】--创建型模式:工厂方法模式

    什么是创建模式 创建型模式是指处理对象创建的设计模式,它们的共同目标是通过某种方式控制对象的创建,以达到更灵活.更可扩展的设计. 创建型模式通常涉及到将对象的创建与使用分离,通过专门的工厂类.构造函数 ...

  7. java/android 设计模式学习笔记(3)---工厂方法模式

    这篇来介绍一下工厂方法模式(Factory Method Pattern),在实际开发过程中我们都习惯于直接使用 new 关键字用来创建一个对象,可是有时候对象的创造需要一系列的步骤:你可能需要计算或 ...

  8. JAVA设计模式是个什么玩意儿_01_工厂方法模式

    1. 前言 工厂方法模式(Factory Method) 该模式属于创建型设计模式. 2. 定义 摘自<研磨设计模式> 陈臣.王斌 3.代码举例 public interface BMW ...

  9. 大话设计模式读书 笔记(六) 工厂方法模式

    工厂方法模式(Factory Method) 书中通过一个学雷锋的例子,来引出工厂方法模式. 工厂方法模式:定义了一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法使一个类的实例化延迟到其子类 ...

最新文章

  1. android 的中文意思
  2. 开源 免费 java CMS - FreeCMS1.9 全文检索
  3. 计算机网络面试知识总结1
  4. 初次遇见NLP:从词向量到BERT
  5. java怎么删除List中的指定元素
  6. Spring Boot国际化支持
  7. 实战演练丨SCN太大引发ORA-600[2252]
  8. java 集合操作_Java 集合的操作 个人方法总结
  9. SQLServer 2008 r2下载及安装
  10. 刚刚卸任的谷歌搜索及AI负责人,被苹果挖走了
  11. 《Java高级Struts2》教学大纲(云计算) 版本号 编写人 版本描述 V1.0 目录 课程教学目标 5 (一)知识目标 5 (二)能力目标 6 (三)速度目标 6
  12. Mac下配置Nginx负载均衡
  13. 麻省理工18年春软件构造课程阅读04“代码评审”
  14. 三维微分方程组四阶龙格库塔求解
  15. 隐匿函数,二分法 冒泡排序
  16. SQL 升序、降序排列
  17. 君莫笑系列视频学习(2)
  18. 2018-2019 ICPC, NEERC, Northern Eurasia Finals K. King Kog's Reception 线段树
  19. 10个程序员可以接私活的平台和一些建议,兼职必看
  20. android设置图片长宽比例,【教程】安卓保证图片长宽比的同时拉伸图片

热门文章

  1. 了解V模型,W模型,H模型
  2. java静态方法lg(),接受一个整形参数N,返回不大于log2N的最大整数不使用Math方法。
  3. hexo博客主题kaze 配置详细解析
  4. html5如何设置字号,如何设置css中字体大小?
  5. vue日程安排_在Vue项目中用fullcalendar制作日程表的示例代码
  6. data类型的Url格式--url(data:image/gif;base64,AAAA):把小数据直接嵌入到Url中
  7. java bitwise_java – Bitwise不对一串位操作
  8. 廖雪峰python视频教程-廖雪峰Python教程的配套视频教程,全套完整版!
  9. python怎么保存到桌面_python3应用windows api对后台程序窗口及桌面截图并保存的方法...
  10. RJ TextEd 中文绿色版下载