• 工厂方法模式概述

工厂方法模式是为了弥补简单工厂模式的不足并且继承它的优点而延生出的一种设计模式,属于GoF中的一种。它能更好的符合开闭原则的要求。

定义:定义了一个用于创建对象的接口,但是让子类决定将哪一个类实例化。即让类的实例化延迟到子类


举个例子:大众汽车公司想必大家都不陌生,它旗下也有不少汽车品牌。大众汽车公司就好比一个汽车工厂,负责生产和销售汽车。它可以为客户提供一个客户需要的汽车。但是,如果客户需要的汽车大众公司目前还没有,但是公司想要盈利,就必须为此而设计汽车,在这种情况下,大众公司就要新添加一种汽车,同时要修改公司内部的生产环境(也就是工厂类的代码)。这就是简单工厂模式的运行情况。简单而言,就是工厂类(汽车公司)什么都要干,要修改必须大动干戈。因而一定程度上违背了开闭原则。而工厂方法模式则不一样,大众汽车公司不在总公司生产汽车,而是成立分公司,收购别的公司,成立具有针对性的汽车工厂专门生产对应的汽车。若客户的大量需求得不到满足,则总公司就另外成立新的二级公司(新品牌汽车的工厂)生产汽车,从而在不修改具体工厂的情况下引进新的产品。正如大众集团的收购一样。以下为简单工厂模式工厂方法模式的区别:

 

  • 工厂方法模式的结构与实现

结构:

  1. Product(抽象产品):定义产品的接口,是工厂方法模式所创建对象的公共父类(生产汽车)
  2. ConcreteProduct(具体产品):实现了抽象产品的接口,某类型的具体产品由专门的工厂创建(如具体类型的汽车)
  3. Factory(抽象工厂):它声明了工厂方法,用于返回一个产品。工厂方法模式的核心,所有创建对象的工厂必须实现该接口(创建生产汽车的工厂)
  4. ConcreteFactory(具体工厂):抽象工厂类的子类,实现了抽象工厂中声明的工厂方法,返回一个具体产品类的实例(对应具体的某一个汽车工厂)

实现:(日志记录器)

实现:

 //Logger.cs  日志记录器接口 充当抽象产品接口
namespace FactoryMethodSample
{
interface Logger
{
void WriteLog();//抽象产品方法
}
} //DatabaseLogger 数据库日志记录器 具体产品
namespace FactoryMethodSample
{
class DatabaseLogger : Logger
{
public void WriteLog()
{
//数据库日志记录
}
}
} //FileLogger 文件日志记录器 具体产品
namespace FactoryMethodSample
{
class FileLogger : Logger
{
public void WriteLog()
{
//文件日志记录
}
}
} //日志记录器工厂接口,充当抽象工厂
namespace FactoryMethodSample
{
interface LoggerFactory
{
Logger CreateLogger();//抽象工厂方法
}
}
//DatabaseLoggerFactory 数据库日志记录器工厂类,具体工厂
namespace FactoryMethodSample
{
class DatabaseLoggerFactory : LoggerFactory
{
public Logger CreateLogger()
{
//连接数据库
//创建记录器对象
Logger logger = new DatabaseLogger();
...
return logger;
}
}
}
//FileLoggerFactory 文件日志记录器工厂类,具体工厂
namespace FactoryMethodSample
{
class FileLoggerFactory : LoggerFactory
{
public Logger CreateLogger()
{
//创建文件日志记录器
Logger logger = new FileLogger();
...
return logger;
}
}
}
//Program 客户端测试
namespace FactoryMethodSample
{
class Program
{ static void Main(string [] args)
{
LoggerFactory factory;//抽象工厂
Logger logger;//抽象产品
factory = new FileLoggerFactory();//new DatabaseLoggerFactory 可以更换为数据库日志记录器
logger = factory.CreateLogger();//抽象工厂方法
logger.WriteLog();//抽象产品方法
....
}
//如果要添加新的日志记录器,只要增加新的具体工厂类,并在客户端中修改具体工厂的类名便可以,从而避免了对原类的修改
}
}
  • 工厂方法模式的重载

在某种情况下,可以用不同的方式来初始化一个产品类,在Logger记录器中,连接数据库的操作可以不用在每次CreateLog后再传入。而是可以将相关参数封装在一个object中,通过object对象将参数传入工厂类中,或者在参数列表中给出连接方式来连接数据库。为此,可以提供一组重载的工厂方法,以不同的方式创建产品。

代码修改如下:

 namespace FactoryMethodSample
{
interface LoggerFactory
{
Logger CreateLogger();//抽象工厂方法
Logger CreateLogger(string args);
Logger CreateLogger(object obj);
}
} //DatabaseLoggerFactory 数据库日志记录器工厂类,具体工厂
namespace FactoryMethodSample
{
class DatabaseLoggerFactory : LoggerFactory
{
public Logger CreateLogger()
{
//连接数据库
//创建记录器对象
Logger logger = new DatabaseLogger();
...
return logger;
}
} class DatabaseLoggerFactory : LoggerFactory
{
public Logger CreateLogger(string args)
{
//用args连接数据库
//
Logger logger = new DatabaseLogger();
...
return logger;
}
} class DatabaseLoggerFactory : LoggerFactory
{
public Logger CreateLogger(object obj)
{
//将参数封装在obj中来连接数据库
Logger logger = new DatabaseLogger();
...
return logger;
}
}
}
  • 工厂方法模式的隐藏

在客户端中,为简化使用,可以隐藏工厂方法。在工厂类调直接调用产品类的方法,在客户端中无需用工厂方法创建产品对象,直接使用工厂对象即可调用所创建的产品对象中的业务方法

代码修改如下:

 //LoggerFactory 修改
abstract class LoggerFactory//改接口为抽象类
{
public void WriteLog()//工厂类直接调用日志记录器的WriteLog();
{
Logger logger = this.CreateLogger();
logger.WriteLog();
}
public abstract Logger CreateLogger();
} //客户端修改如下
namespace FactoryMethodSample
{
class Program
{
static void Main(string [] args)
{
LoggerFactory factory;
//Load configuration file;
string factoryString = ConfigurationManager.AppSettings["factory"];
//反射生成对象
factory = (LoggerFactory)Assembly.Load("FactoryMethodSample").CreateInstance(factoryString);
factory.WriteLog();//直接使用工厂对象调用产品对象的业务方法
}
}
}
  • 工厂方法模式的优缺点和适用环境

  (1)工厂方法模式的优点

    (1)用户只需要关心产品对应的工厂,甚至无需关心创建细节或具体产品类的类名  
    (2)基于工厂角色和产品的多态性设计是工厂模式的关键。它能自主决定如何创建哪种产品对象,而创建细节都封装在具体工厂内部
    (3)在系统要添加新的产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改客户端,也无需修改其他的具体工厂和具体产品,只要添加一个具体工厂和具体产品即可,从而提高系统的可扩展性(符合开闭原则) 

  (2)工厂方法模式的缺点

    (1)在添加新产品时,要编写新的具体产品类,并要提供与之对应的具体工厂类。系统软件个数也成对增加,从而增加了系统的复杂度,带来更多开销
    (2)由于系统的可扩展性,在客户端中要引入抽象层进行定义,从而增加了系统的抽象性和理解难度

  (3)工厂方法模式的适用环境

    (1)客户端不需要知道它需要的对象的类。只需知道对应的工厂即可

    (2)抽象工厂类通过子类来指定创建那哪个对象。即抽象工厂类只需要提供一个创建产品的接口,而由其子类确定具体要创建的对象,利用多态性和里氏代换原则,子类对象将覆盖父类对象,从而使系统更容易扩展 


  • 在日志记录器实例中,在更换日志记录器时需要修改客户端代码。为了按照开闭原则的要求执行,可以在不修改任何客户端代码的基础上更换或增加新的日志记录方式。即通过配置文件程序集的反射机制,读取配置文件中存储的类名字符串生成对象。这里没有进行讲解,可以自行搜索..~_~!!

工厂方法模式(Factory Method Pattern)的更多相关文章

  1. 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern)

    原文:乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pa ...

  2. 【设计模式】工厂方法模式 Factory Method Pattern

    在简单工厂模式中产品的创建统一在工厂类的静态工厂方法中创建,体现了面形对象的封装性,客户程序不需要知道产品产生的细节,也体现了面向对象的单一职责原则(SRP),这样在产品很少的情况下使用起来还是很方便 ...

  3. 二十四种设计模式:工厂方法模式(Factory Method Pattern)

    工厂方法模式(Factory Method Pattern) 介绍定义一个用于创建对象的接口,让子类决定将哪一个类实例化.Factory Method使一个类的实例化延迟到其子类. 示例有SqlMes ...

  4. 设计模式-03工厂方法模式(Factory Method Pattern)

    插曲.简单工厂模式(Simple Factory Pattern) 介绍工厂方法模式之前,先来做一个铺垫,了解一下简单工厂模式,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背 ...

  5. 六个创建模式之工厂方法模式(Factory Method Pattern)

    问题: 在使用简单工厂模式的时候,如果添加新的产品类,则必需修改工厂类,违反了开闭原则. 定义: 定义一个用于创建对象的接口,让子类决定具体实例化哪个产品类.此时工厂和产品都具有相同的继承结构,抽象产 ...

  6. 设计模式之工厂方法模式(Factory Method Pattern)

    一.工厂方法模式的诞生 在读这篇文章之前,我先推荐大家读<设计模式之简单工厂模式(Simple Factory Pattern)>这篇文档.工厂方法模式是针对简单工厂模式中违反开闭原则的不 ...

  7. 【UE4 设计模式】工厂方法模式 Factory Method Pattern 及自定义创建资源

    概述 描述 又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式,或者多态工厂(Polymorphic Factory)模式 工厂父类负责定义创建产品对象的公共接口,而工厂子类 ...

  8. C#设计模式——工厂方法模式(Factory Method Pattern)

    一.概述在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口.如何应对这种变化?如何提供一种封装机制来隔离出“这个易变对象 ...

  9. php工厂方法模式(factory method pattern)

    继续练 <?php /* The factory method pattern deals with the problem of creating objects without having ...

随机推荐

  1. robot framework之弹出窗口的处理关键字实战

    1.1  弹出窗口的处理关键字 5.8.1 Alert Should Be Present关键字 按F5 查看Alert Should Be Present关键字的说明,如下图

  2. C/C++ 数据结构之算法

    数据结构中的排序算法. 排序算法的相关知识: (1)排序的概念:所谓排序就是要整理文件中的记录,使之按关键字递增(或递减)次序排列起来. (2)稳定的排序方法:在待排序的文件中,若存在多个关键字相同的 ...

  3. PAT1031:Hello World for U

    1031. Hello World for U (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Giv ...

  4. Java NIO核心组件简介

    原文链接:http://tutorials.jenkov.com/java-nio/overview.html NIO包含下面几个核心的组件: Channels Buffer Selector 整个N ...

  5. 第四章——训练模型(Training Models)

    前几章在不知道原理的情况下,已经学会使用了多个机器学习模型机器算法.Scikit-Learn很方便,以至于隐藏了太多的实现细节. 知其然知其所以然是必要的,这有利于快速选择合适的模型.正确的训练算法. ...

  6. MIT KIT OpenID Connect Demo Client

    Hello world! You are NOT currently logged in. This example application is configured with several pa ...

  7. UsernamePasswordAuthenticationToken

    UsernamePasswordAuthenticationToken继承AbstractAuthenticationToken实现Authentication所以当在页面中输入用户名和密码之后首先会 ...

  8. Vue.js中前端知识点总结笔记

    1.框架和库的区别: 框架:framework 有着自己的语法特点.都有对应的各个模块库 library 专注于一点 框架的好处: 1.提到代码的质量,开发速度 2.提高代码的复用率 3.降低模块之间 ...

  9. Python List 删除元素

    1. 使用del删除指定元素 li = [1, 2, 3, 4] del li[3] print(li) # Output [1, 2, 3] 2. 使用list方法pop删除元素 li = [1, ...

  10. 字符串匹配KMP算法的讲解C++

    转自http://blog.csdn.net/starstar1992/article/details/54913261 也可以参考http://blog.csdn.net/liu940204/art ...