C#设计模式系列:工厂方法模式(Factory Method)
1. 工厂方法模式简介
1.1 定义
工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式是以一个类的实例化延迟到其子类。
Factory Method模式用于在不指定待创建对象的具体类的情况下创建对象。
Factory Method模式的主要意图是隐藏对象创建的复杂性。Client通常不指定要创建的具体类,Client将面向接口或抽象类进行编码,让Factory类负责创建具体的类型。通常Factory类有一个返回抽象类或者接口的静态方法。Client通常提供某种信息让Factory类使用提供的信息来确定创建并返回哪个子类。
将创建子类的责任抽象出来的好处是允许Client完全无需考虑依赖类是如何创建的,这遵守依赖倒置原则(Dependency Inversion Principle,DIP)。Factory Method模式另外一个好处是把负责对象创建的代码集中起来,如果需要修改对象生成方式,可以轻松定位并更新,而不会影响到依赖它的代码。
1.2 使用频率
高
2. 工厂方法模式结构
2.1 结构图

2.2 参与者
工厂方法模式参与者:
◊ Product:Product角色,定义工厂方法所创建的对象的接口
◊ ConcreteProduct:具体Product角色,实现Product接口
◊ Factory
° 抽象的工厂角色,声明工厂方法,该方法返回一个Product类型的对象
° Factory可以定义一个工厂方法的默认实现,返回一个默认的ConcreteProduct对象。可以调用工厂方法以创建一个Product对象。
◊ ConcreteFactory:具体的工厂角色,创建具体Product的子工厂,重写工厂方法以返回一个ConcreteProduct实例
3. 工厂方法模式结构实现

Product.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignPatterns.FactoryMethodPattern.Structural
{
/// <summary>
/// 定义Product抽象类,Client调用Product抽象类,并由Factory来创建具体类。
/// </summary>
public abstract class Product
{
}
}
ConcreteProductA.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignPatterns.FactoryMethodPattern.Structural
{
public class ConcreteProductA : Product
{
}
}
ConcreteProductB.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignPatterns.FactoryMethodPattern.Structural
{
public class ConcreteProductB : Product
{
}
}
Factory.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignPatterns.FactoryMethodPattern.Structural
{
public abstract class Factory
{
public abstract Product CreateProduct();
}
}
ConcreteFactoryA.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignPatterns.FactoryMethodPattern.Structural
{
public class ConcreteFactoryA : Factory
{
public override Product CreateProduct()
{
return new ConcreteProductA();
}
}
}
ConcreteFactoryB.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignPatterns.FactoryMethodPattern.Structural
{
public class ConcreteFactoryB : Factory
{
public override Product CreateProduct()
{
return new ConcreteProductB();
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using DesignPatterns.FactoryMethodPattern.Structural; namespace DesignPatterns.FactoryMethodPattern
{
class Program
{
static void Main(string[] args)
{
Factory[] factories = new Factory[];
factories[] = new ConcreteFactoryA();
factories[] = new ConcreteFactoryB(); foreach (Factory factory in factories)
{
Product product = factory.CreateProduct();
Console.WriteLine("Created {0}", product.GetType().Name);
}
}
}
}
运行输出:
Created ConcreteProductA
Created ConcreteProductB
请按任意键继续. . .
4. 工厂方法模式实践应用
假设你现在是一家KFC的管理者,要给顾客提供一系列的食品,如鸡翅、鸡腿等,顾客没要求一种食品,KFC应当可以很快生产出来,采用工厂模式来实现这个过程。

KFCFood.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignPatterns.FactoryMethodPattern.Practical
{
/// <summary>
/// 抽象的KFC食品,Product角色
/// </summary>
public abstract class KFCFood
{
public abstract void Display();
}
}
Chicken.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignPatterns.FactoryMethodPattern.Practical
{
public class Chicken : KFCFood
{
public override void Display()
{
Console.WriteLine("鸡腿 + 1");
}
}
}
Wings.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignPatterns.FactoryMethodPattern.Practical
{
public class Wings : KFCFood
{
public override void Display()
{
Console.WriteLine("鸡翅 + 1");
}
}
}
IKFCFactory.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignPatterns.FactoryMethodPattern.Practical
{
public interface IKFCFactory
{
KFCFood CreateFood();
}
}
ChickenFactory.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignPatterns.FactoryMethodPattern.Practical
{
public class ChickenFactory : IKFCFactory
{
public KFCFood CreateFood()
{
return new Chicken();
}
}
}
WingsFactory.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace DesignPatterns.FactoryMethodPattern.Practical
{
public class WingsFactory : IKFCFactory
{
public KFCFood CreateFood()
{
return new Wings();
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using DesignPatterns.FactoryMethodPattern.Practical; namespace DesignPatterns.FactoryMethodPattern
{
class Program
{
static void Main(string[] args)
{
// 定义一个鸡腿工厂
IKFCFactory factory = new ChickenFactory();
// 生产鸡腿
KFCFood food1 = factory.CreateFood();
food1.Display();
// 生产鸡腿
KFCFood food2 = factory.CreateFood();
food2.Display();
// 生产鸡腿
KFCFood food3 = factory.CreateFood();
food3.Display();
}
}
}
运行输出:
鸡腿 +
鸡腿 +
鸡腿 +
请按任意键继续. . .
在以上例子中,使用工厂模式的好处:
1>. 客户端在创建产品的时候只需指定一个子工厂而无需了解该子工厂具体创建什么产品;
2>. 当需求有变动,要不food1、food2、food3均改为“鸡翅”的时候,只需将
IKFCFactory factory = new ChickenFactory();
改为
IKFCFactory factory = new WingsFactory();
即可;
3>. 在工厂方法模式中,核心的工厂类不是负责所有产品的创建,而是将具体的创建工作交给子类ConcreteFactory去做。工厂类仅仅负责给出具体工厂必须实现的接口,而不涉及哪一个产品类被实例化这种细节。工厂方法模式可以使得系统在不需要修改原有代码的情况下引进新产品,如现在要增加一种新的产品“薯条”,则无需修改原有代码,只需增加一个“薯条”产品类和一个相应的“薯条”子工厂即可。在工厂方法模式中,子工厂与产品类往往具有平行的等级结构,它们之间一一对应。
5. 工厂方法模式应用分析
5.1 工厂方法模式适用情形
◊ 当一个类不知道它所必须创建的对象的类信息的时候
◊ 当一个类希望由它来指定它所创建的对象的时候
◊ 当类将创建对象的职责委托给多个辅助子类中的某一个,并且希望将哪一个辅助之类是代理者这一信息局部化的时候
5.2 工厂方法模式特点
◊ 使用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活
◊ 工厂方法模式通过面向对象的手法,将所要创建的具体对象的创建工作延迟到子类,从而提供了一种扩展的策略,较好的解决了紧耦合的关系
◊ 工厂方法模式遵守依赖倒置原则(Dependency Inversion Principle,DIP)
5.3 工厂方法模式与简单工厂模式区别
◊ 工厂方法模式和简单工厂模式在结构上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体工厂类上。工厂方法模式可以允许很多具体工厂类从抽象工厂类中将创建行为继承下来,从而可以成为多个简单工厂模式的综合,进而推广了简单工厂模式。
◊ 工厂方法模式退化后可以变得很像简单工厂模式。如果非常确定一个系统只需要一个具体工厂类,那么就不妨把抽象工厂类合并到具体的工厂类中去。由于只有一个具体工厂类,所以不妨将工厂方法改成为静态方法,这时候就得到了简单工厂模式
5.4 工厂方法模式与抽象工厂模式区别
| 工厂方法模式 | 抽象工厂模式 |
|---|---|
| 只有一个抽象产品类(Product) | 有多个抽象产品类(AbstractProductA、AbstractProductA) |
|
具体工厂类只能创建一个具体产品类的实例。 ConcreteFactoryA生产ConcreteProductA,ConcreteFactoryB生产ConcreteProductB |
具体工厂类可以创建多个具体产品类的实例。 ConcreteFactory1生产ConcreteProductA1、ConcreteProductB1,ConcreteFactory2生产ConcreteProductA2、ConcreteProductB2 |
C#设计模式系列:工厂方法模式(Factory Method)的更多相关文章
- 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern)
原文:乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pa ...
- 设计模式-03工厂方法模式(Factory Method Pattern)
插曲.简单工厂模式(Simple Factory Pattern) 介绍工厂方法模式之前,先来做一个铺垫,了解一下简单工厂模式,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背 ...
- 【设计模式】工厂方法模式 Factory Method Pattern
在简单工厂模式中产品的创建统一在工厂类的静态工厂方法中创建,体现了面形对象的封装性,客户程序不需要知道产品产生的细节,也体现了面向对象的单一职责原则(SRP),这样在产品很少的情况下使用起来还是很方便 ...
- 二十四种设计模式:工厂方法模式(Factory Method Pattern)
工厂方法模式(Factory Method Pattern) 介绍定义一个用于创建对象的接口,让子类决定将哪一个类实例化.Factory Method使一个类的实例化延迟到其子类. 示例有SqlMes ...
- 设计模式之工厂方法模式(Factory Method Pattern)
一.工厂方法模式的诞生 在读这篇文章之前,我先推荐大家读<设计模式之简单工厂模式(Simple Factory Pattern)>这篇文档.工厂方法模式是针对简单工厂模式中违反开闭原则的不 ...
- 设计模式之 - 工厂方法模式 (Factory Method design pattern)
1. 模式意图: 定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类. 2. 别名(Virtual Constructor) 3. 结构 4. 工厂方法模式C ...
- 【UE4 设计模式】工厂方法模式 Factory Method Pattern 及自定义创建资源
概述 描述 又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式,或者多态工厂(Polymorphic Factory)模式 工厂父类负责定义创建产品对象的公共接口,而工厂子类 ...
- 工厂方法模式-Factory Method(Java实现)
工厂方法模式-Factory Method 工厂方法模式定义一个用于创建对象的接口,让子类决定实例化哪一个类.工厂方法让实例化的具体内容交给子类工厂来进行. 本文中的例子是这样的. 生产一个身份证, ...
- 浅谈C++设计模式之工厂方法(Factory Method)
为什么要用设计模式?根本原因是为了代码复用,增加可维护性. 面向对象设计坚持的原则:开闭原则(Open Closed Principle,OCP).里氏代换原则(Liskov Substitution ...
- PHP 设计模式系列 —— 工厂方法模式(Factory Method)(转)
1.模式定义 定义一个创建对象的接口,但是让子类去实例化具体类.工厂方法模式让类的实例化延迟到子类中. 2.问题引出 框架需要为多个应用提供标准化的架构模型,同时也要允许独立应用定义自己的域对象并对其 ...
随机推荐
- Html 基础介绍 基础标签
<head> <!-- 设置编码格式 --> <meta charset="UTF-8"> <!-- 设置作者 --> <me ...
- winform下的简易播放器
编写这个播放器,遇到很多问题,比如目前只实现了wav音频文件的播放,而对于这个图中中间所标注的按钮 不能实现让其暂停的功能,同时当点击的时候,让其文本变为"▷",对于这部分功能不知 ...
- 【HDU2896】病毒侵袭 AC自动机
[HDU2896]病毒侵袭 Problem Description 当太阳的光辉逐渐被月亮遮蔽,世界失去了光明,大地迎来最黑暗的时刻....在这样的时刻,人们却异常兴奋--我们能在有生之年看到500年 ...
- CF750E New Year and Old Subsequence
讲道理好久没有做过题了.. 题目大意 给出长度为$n$的只含数字的串,有$q$个询问,每次询问一段区间,问最少删去多少个数才能变成只含2017子序列而不含2016子序列 吉爸爸好强啊.. 定义$a_{ ...
- Swift的关键字
在声明中使用关键字 let :声明一个常量 var :声明一个变量 class :声明一个类 static :静态的 deinit :反初始化方法?析构方法 init :构造方法?初始化方法 en ...
- android开发中使不同的listview同时联动
在做一个Android程序时,需要在一个屏幕上显示两个不同的listview,开始用< linearlayout>包裹这两个listview在<ScrollView >设置时, ...
- 在一定[min,max]区间,生成n个不重复的随机数的封装函数
引:生成一个[min,max]区间的一个随机数,随机数生成相关问题参考→链接 var ran=parseInt(Math.random()*(max-min+1)+min); //生成一个[min,m ...
- 关于i和j
算法课无聊随手写了段c代码,发现了个问题,就要下课了,先记一下 for(int i = 0; i < 100; i ++) for(int j = 0; j < 100000; j ++) ...
- JDBC的连接和增删改和查找
package Test2;import java.sql.*;import java.sql.DriverManager;import java.sql.SQLException;public cl ...
- VIM配置
Linux下的编辑器以vim和emacs为主流,一个编辑器之神,一个是神的编辑器. 本文以主要介绍如何在linux下以vim为基础搭建一个比较顺手的代码编辑器. 有两种比较流行的方式: 自动安装 手动 ...