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.问题引出 框架需要为多个应用提供标准化的架构模型,同时也要允许独立应用定义自己的域对象并对其 ...
随机推荐
- homebrew update 出现Failure while executing: git pull --quiet origin refs/heads/master:refs/remotes/origin/master解决方案
具体可以参考https://github.com/Homebrew/homebrew/issues/21002 cd /usr/local git status git reset --hard or ...
- 【生活没有希望】hdu1166敌兵布阵 线段树
线段树水题刷刷,生活没有希望 最近看到代码跟树状数组差不多短的非递归线段树,常数也很小——zkw线段树 于是拿道水题练练手 短到让人身无可恋 ;pos;pos/=) a[pos]+=x;} ,ans= ...
- Docker 创建php 开发环境遇到的权限问题解决方案
最近我将公司的开发,和测试环境都运行到docker 上面,因为开发,测试基本都是装代码拉到本址,然后,再装目录,挂载到镜像目录中如:我用的是docker-compose # development.y ...
- 关于MySQL 的LEFT JOIN ON的问题
今天在查询视图时,遇到了一个问题. 因为mysq不能嵌套select的子查询.所以我把子查询建成了视图b,主查询通过left join on关联视图b ,形成视图a. 由于视图b中也有left joi ...
- 响应式web网站设计制作方法
在研究响应式的时候,记录了一些感想,分享出来,抛砖引玉,希望可以和大家一起讨论.总结下来,响应式比之前想象的要复杂得多.1. ie9以下(不包括ie9)采用ie条件注释,为ie8以及一下单独开一个样式 ...
- 如何创建一个Edge 浏览器扩展
随着微软Windows 10 年度更新的发布,数次延宕的Edge 扩展功能终于得到了官方正式支持.我在我的另外一个博客上发布了如何创建一个Edge 浏览器扩展的博文,链接如下: https://blo ...
- ★★★Oracle sql 传参特别注意★★★
最近遇到一个非常烦人的问题,用传参的方式执行sql语句结果老是报 Oracle ORA-01722: 无效数字 一直无法找到原因. 表结构大致如下: table test_station ( tblR ...
- 移动开发可能用到的css单位
众所周知CSS技术我们虽然很熟悉,在使用的过程却很容易被困住,这让我们在新问题出现的时候变得很不利.随着web继续不断地发展,对于新技术新 解决方案的要求也会不断增长.因此,作为网页设计师和前端开发人 ...
- .NET开源OpenID和OAuth解决方案Thinktecture IdentityServer
现代的应用程序看起来像这样: 典型的交互操作包括: 浏览器与 web 应用程序进行通信 Web 应用程序与 web Api (有时是在他们自己的有时代表用户) 通信 基于浏览器的应用程序与 web A ...
- CentOS 7 安装RabbitMQ 3.3
1.安装erlang 语言环境 安装依赖文件 #yum install ncurses-devel 进入 http://www.erlang.org/download.html 选择源文件下载 wge ...