设计模式的艺术之道--工厂方法模式
来源:互联网 发布:淘宝9块9包邮怎么赚钱 编辑:程序博客网 时间:2024/05/18 23:54
设计模式的艺术之道–工厂方法模式
声明:本系列为刘伟老师博客内容总结(http://blog.csdn.net/lovelion),博客中有完整的设计模式的相关博文,以及作者的出版书籍推荐
本系列内容思路分析借鉴了刘伟老师的博文内容,同时改用C#代码进行代码的演示和分析(Java资料过多 C#表示默哀).
本系列全部源码均在文末地址给出。
本系列开始讲解创建型模式,顾名思义,这类模式主要是为了解决类的创建问题。
- 创建型模式(Creational Pattern)关注对象的创建过程。分析你怎么来的
- 创建型模式对类的实例化过程进行了抽象,对用户隐藏了类的实例的创建细节。客户不知道你怎么来的
- 创建型模式描述如何将对象的创建和使用分离,让用户在使用对象时无须关心对象的创建细节。你用就行,别管我怎么来的。
- 创建型模式关注点 创建什么(What) 由谁创建(Who) 何时创建(When)
6种常见的创建型模式
工厂方法模式
简单工厂模式虽然简单,但存在一个很严重的问题。当系统中需要引入新产品时,由于静态工厂方法通过所传入参数的不同来创建不同的产品,这必定要修改工厂类的源代码,将违背“开闭原则”,如何实现增加新产品而不影响已有代码?
1.1定义
- 工厂方法模式 (Simple Factory Pattern):定义一个用于创建对象的接口,但是让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。
- 老板开始雇人(工厂)干活了,炒菜的炒菜(产品),做面的做面(产品),做点心的做点心(产品)。老板把任务分配下去自己不管了。
- 工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象。
1.2情景实例
问题描述
- 日志记录器(Logger)设计
菜鸟软件公司欲开发一个系统运行日志记录器,该记录器可以通过多种途径保存系统的运行日志,如通过文件记录或数据库记录,用户可以通过修改配置文件灵活地更换日志记录方式。在设计各类日志记录器时,菜鸟公司的开发人员发现需要对日志记录器进行一些初始化工作,初始化参数的设置过程较为复杂,而且某些参数的设置有严格的先后次序,否则可能会发生记录失败。如何封装记录器的初始化过程并保证多种记录器切换的灵活性是Sunny公司开发人员面临的一个难题。
初步思路
LoggerFactory充当创建日志记录器的工厂,提供了工厂方法createLogger()用于创建日志记录器,Logger是抽象日志记录器接口,其子类为具体日志记录器。其中,工厂类LoggerFactory代码片段如下所示。
//日志记录器工厂 class LoggerFactory { //静态工厂方法 public static Logger createLogger(String args) { if(args.equalsIgnoreCase("db")) { //连接数据库,代码省略 //创建数据库日志记录器对象 Logger logger = new DatabaseLogger(); //初始化数据库日志记录器,代码省略 return logger; } else if(args.equalsIgnoreCase("file")) { //创建日志文件 //创建文件日志记录器对象 Logger logger = new FileLogger(); //初始化文件日志记录器,代码省略 return logger; } else { return null; } } }
现有缺点(未来变化)
- (1) 用户可能需要更换日志记录方式,日志工厂类需要单独修改,
- (2如果增加新类型的日志记录器,必须修改静态工厂方法的业务逻辑,违反了“开闭原则”。
- (3) 工厂类过于庞大,包含了大量的if…else…代码,导致维护和测试难度增大。
如何改进
引入工厂方法模式
- 对具体的产品类,单独提升出一个产品的工厂类
- 针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构
UML类图
实例关键代码
namespace FactoryMethod{ interface Logger { //抽象产品 void WriteLog(); } class FileLogger : Logger { //具体产品 public void WriteLog() { Console.WriteLine("文件日志记录。"); } } interface LoggerFactory { Logger CreateLogger(); } class FileLoggerFactory : LoggerFactory { // 具体产品工厂 public Logger CreateLogger() { //创建文件日志记录器对象 Logger logger = new FileLogger(); //创建文件,代码省略 return logger; } } class Program { //客户端调用 static void Main(string[] args) { LoggerFactory factory; Logger logger; //读取配置文件 string factoryString = ConfigurationManager.AppSettings["factory"]; //反射生成对象 factory = (LoggerFactory)Assembly.Load("FactoryMethod").CreateInstance(factoryString); logger = factory.CreateLogger(); logger.WriteLog(); Console.ReadLine(); } }}
1.3模式分析
动机和意图
- 在简单工厂模式中,所有的产品都由同一个工厂创建,工厂类职责较重
- 具体产品与工厂类之间的耦合度高,严重影响了系统的灵活性和扩展性
一般结构
- 工厂方法模式包含如下角色:
- Factory:工厂角色 负责创建产品
- Product:抽象产品角色 产品的抽象归类提升
- ConcreteProduct:具体产品角色 工厂输出的产品
- ConcreteFactory : 具体工厂 生产具体产品的具体工厂
改进的优点
- 向客户隐藏了哪种具体产品类将被实例化这一细节,运行时自行选择确定
- 如何创建这个对象的细节则完全封装在具体工厂内部
- 在系统中加入新产品时,完全符合开闭原则
现存的缺点
- 系统中类的个数将成对增加,在一定程度上增加了系统的复杂度
- 增加了系统的抽象性和理解难度
优化空间
- 工厂的造产品方法可以进行多种参数的重载
- 工厂方法的隐藏,在工厂类中将直接调用产品类的业务方法
- 客户端无须调用工厂方法创建产品,
适用场景
(1) 客户端不知道它所需要的对象的类,只需要知道所对应的工厂即可,具体产品对象由具体工厂类创建)。
(2) 抽象工厂类通过其子类来指定创建哪个对象。
举例:小王去王记饭馆吃饭(小王要吃面,告诉了老板,老板吩咐王麻子厨师去做) 图片读取器(png,jpg,gif) 每种格式对应一个工厂和产品
实例源代码
GitHub地址
百度云地址:链接: https://pan.baidu.com/s/1hsOXlTa 密码: vgtv
- 设计模式的艺术之道--工厂方法模式
- 设计模式的艺术之道--简单工厂模式
- 设计模式的艺术之道--抽象工厂模式
- 设计模式的艺术之道--模板方法模式
- 大话设计模式之简单工厂模式、抽象工厂模式及工厂方法模式的比较
- 大话设计模式之简单工厂模式、抽象工厂模式及工厂方法模式的比较
- 设计模式的艺术之道--设计模式的基本概念
- 设计模式之工厂方法
- 设计模式之工厂方法
- 设计模式 之 工厂方法
- 设计模式 之 工厂方法
- 设计模式之工厂方法
- 设计模式之工厂方法
- 设计模式之工厂方法
- 设计模式之工厂方法
- 设计模式之工厂方法
- 设计模式之工厂方法
- 设计模式之工厂方法
- 【安全牛学习笔记】Burpsuite
- UnityDecal——贴花方法总结
- 程序员的一点经验
- 前端面试知识必备
- vim代码跳转工具ctags安装及使用
- 设计模式的艺术之道--工厂方法模式
- Centos 7安装禅道
- 搞清this的指向只需问两个问题
- matlab----标签图像分类训练工具
- dedecms修改templets模板文件夹名字
- <转载>eclipse:更改tomcat端口号方法
- 获取Tomcat部署路径的方法
- QT之paintEvent事件
- xftp上传文件状态错误