设计模式的艺术之道--工厂方法模式

来源:互联网 发布:淘宝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

原创粉丝点击