C#设计模式(3)——工厂方法模式(转)
C#设计模式(3)——工厂方法模式
一、引言
在简单工厂模式中讲到简单工厂模式的缺点,有一点是——简单工厂模式系统难以扩展,一旦添加新产品就不得不修改简单工厂方法,这样就会造成简单工厂的实现逻辑过于复杂,然而本专题介绍的工厂方法模式可以解决简单工厂模式中存在的这个问题,下面就具体看看工厂模式是如何解决该问题的。
二、工厂方法模式的实现
工厂方法模式之所以可以解决简单工厂的模式,是因为它的实现把具体产品的创建推迟到子类中,此时工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式就可以允许系统不修改工厂类逻辑的情况下来添加新产品,这样也就克服了简单工厂模式中缺点。下面看下工厂模式的具体实现代码(这里还是以简单工厂模式中点菜的例子来实现):

namespace 设计模式之工厂方法模式
{
/// <summary>
/// 菜抽象类
/// </summary>
public abstract class Food
{
// 输出点了什么菜
public abstract void Print();
} /// <summary>
/// 西红柿炒鸡蛋这道菜
/// </summary>
public class TomatoScrambledEggs : Food
{
public override void Print()
{
Console.WriteLine("西红柿炒蛋好了!");
}
} /// <summary>
/// 土豆肉丝这道菜
/// </summary>
public class ShreddedPorkWithPotatoes : Food
{
public override void Print()
{
Console.WriteLine("土豆肉丝好了");
}
} /// <summary>
/// 抽象工厂类
/// </summary>
public abstract class Creator
{
// 工厂方法
public abstract Food CreateFoddFactory();
} /// <summary>
/// 西红柿炒蛋工厂类
/// </summary>
public class TomatoScrambledEggsFactory:Creator
{
/// <summary>
/// 负责创建西红柿炒蛋这道菜
/// </summary>
/// <returns></returns>
public override Food CreateFoddFactory()
{
return new TomatoScrambledEggs();
}
} /// <summary>
/// 土豆肉丝工厂类
/// </summary>
public class ShreddedPorkWithPotatoesFactory:Creator
{
/// <summary>
/// 负责创建土豆肉丝这道菜
/// </summary>
/// <returns></returns>
public override Food CreateFoddFactory()
{
return new ShreddedPorkWithPotatoes();
}
} /// <summary>
/// 客户端调用
/// </summary>
class Client
{
static void Main(string[] args)
{
// 初始化做菜的两个工厂()
Creator shreddedPorkWithPotatoesFactory = new ShreddedPorkWithPotatoesFactory();
Creator tomatoScrambledEggsFactory = new TomatoScrambledEggsFactory(); // 开始做西红柿炒蛋
Food tomatoScrambleEggs = tomatoScrambledEggsFactory.CreateFoddFactory();
tomatoScrambleEggs.Print(); //开始做土豆肉丝
Food shreddedPorkWithPotatoes = shreddedPorkWithPotatoesFactory.CreateFoddFactory();
shreddedPorkWithPotatoes.Print(); Console.Read();
}
}
}

使用工厂方法实现的系统,如果系统需要添加新产品时,我们可以利用多态性来完成系统的扩展,对于抽象工厂类和具体工厂中的代码都不需要做任何改动。例如,我们我们还想点一个“肉末茄子”,此时我们只需要定义一个肉末茄子具体工厂类和肉末茄子类就可以。而不用像简单工厂模式中那样去修改工厂类中的实现(具体指添加case语句)。具体代码为:

/// <summary>
/// 肉末茄子这道菜
/// </summary>
public class MincedMeatEggplant : Food
{
/// <summary>
/// 重写抽象类中的方法
/// </summary>
public override void Print()
{
Console.WriteLine("肉末茄子好了");
}
}
/// <summary>
/// 肉末茄子工厂类,负责创建肉末茄子这道菜
/// </summary>
public class MincedMeatEggplantFactory : Creator
{
/// <summary>
/// 负责创建肉末茄子这道菜
/// </summary>
/// <returns></returns>
public override Food CreateFoddFactory()
{
return new MincedMeatEggplant();
}
} /// <summary>
/// 客户端调用
/// </summary>
class Client
{
static void Main(string[] args)
{ // 如果客户又想点肉末茄子了
// 再另外初始化一个肉末茄子工厂
Creator minceMeatEggplantFactor = new MincedMeatEggplantFactory(); // 利用肉末茄子工厂来创建肉末茄子这道菜
Food minceMeatEggplant = minceMeatEggplantFactor.CreateFoddFactory();
minceMeatEggplant.Print(); Console.Read();
}
}

三、工厂方法模式的UML图
讲解完工厂模式的具体实现之后,让我们看下工厂模式中各类之间的UML图:

从UML图可以看出,在工厂方法模式中,工厂类与具体产品类具有平行的等级结构,它们之间是一一对应的。针对UML图的解释如下:
Creator类:充当抽象工厂角色,任何具体工厂都必须继承该抽象类
TomatoScrambledEggsFactory和ShreddedPorkWithPotatoesFactory类:充当具体工厂角色,用来创建具体产品
Food类:充当抽象产品角色,具体产品的抽象类。任何具体产品都应该继承该类
TomatoScrambledEggs和ShreddedPorkWithPotatoes类:充当具体产品角色,实现抽象产品类对定义的抽象方法,由具体工厂类创建,它们之间有一一对应的关系。
四、.NET中实现了工厂方法的类
.NET 类库中也有很多实现了工厂方法的类,例如Asp.net中,处理程序对象是具体用来处理请求,当我们请求一个*.aspx的文件时,此时会映射到System.Web.UI.PageHandlerFactory类上进行处理,而对*.ashx的请求将映射到System.Web.UI.SimpleHandlerFactory类中(这两个类都是继承于IHttpHandlerFactory接口的),关于这点说明我们可以在“C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\Web.Config”文件中找到相关定义,具体定义如下:
<httpHandlers>
<add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True" />
<add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True" />
<add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True" />
</httpHandlers>
下面我们就具体看下工厂方法模式在Asp.net中是如何实现的,如果对一个Index.aspx页面发出请求时,将会调用PageHandlerFactory中GetHandler方法来创建一个Index.aspx对象,它们之间的类图关系如下:

五、总结
工厂方法模式通过面向对象编程中的多态性来将对象的创建延迟到具体工厂中,从而解决了简单工厂模式中存在的问题,也很好地符合了开放封闭原则(即对扩展开发,对修改封闭)。
如果您认为这篇文章还不错或者有所收获,您可以通过右边的“打赏”功能 打赏我一杯咖啡【物质支持】,也可以点击右下角的【店长推荐】按钮【精神支持】,因为这两种支持都是我继续写作,分享的最大动力
C#设计模式(3)——工厂方法模式(转)的更多相关文章
- C#设计模式(3)——工厂方法模式
一.概念:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类. 二.代码实现 namespace 设计模式之工厂方法模式 { /// <summary&g ...
- 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern)
原文:乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pa ...
- Java设计模式之工厂方法模式(转) 实现是抽象工厂?
Java设计模式之工厂方法模式 责任编辑:覃里作者:Java研究组织 2009-02-25 来源:IT168网站 文本Tag: 设计模式 Java [IT168 技术文章] ...
- php设计模式之工厂方法模式
php设计模式之工厂方法模式 工厂方法模式 工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Pol ...
- java 23 - 1 设计模式之工厂方法模式
转载: JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式)
- Java设计模式 之 工厂方法模式
1. 使用设计模式的好处:可提高代码的重复性,让代码更容易被他人理解,保证代码的可靠性. 2. 工厂模式定义:就是创建一个工厂类来创建你需要的类,工厂模式包括工厂模式和抽象工厂模式,抽象工厂模式是工厂 ...
- Android设计模式系列--工厂方法模式
工厂方法模式,往往是设计模式初学者入门的模式,的确,有人称之为最为典型最具启发效果的模式.android中用到了太多的工厂类,其中有用工厂方法模式的,当然也有很多工厂并不是使用工厂方法模式的,只是工具 ...
- 设计模式之 - 工厂方法模式 (Factory Method design pattern)
1. 模式意图: 定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类. 2. 别名(Virtual Constructor) 3. 结构 4. 工厂方法模式C ...
- 再起航,我的学习笔记之JavaScript设计模式06(工厂方法模式)
上一次已经给大家介绍了简单工厂模式,相信大家对创建型设计模式有了初步的了解,本次我将给大家介绍的是工厂方法模式. 工厂方法模式 工厂方法模式(Factory Method):通过对产品类的抽象使其创建 ...
随机推荐
- 【iCore1S 双核心板_ARM】例程十七:FSMC实验——读写FPGA
实验现象: 先烧写FPGA程序,再烧写ARM程序,ARM程序烧写完毕后即开始读写RAM测试,测试成功,绿色ARM·LED亮,测试失败,红色ARM·LED闪烁. 核心代码: int main(void) ...
- 优化实现Mobile/Bumped Diffuse
在上一篇帖子的基础上增加一张法线贴图即可: Shader "James/Scene/Bumped_Diffuse" { Properties { _MainTex ("B ...
- sql 视图 字段条件统计
) FModelCode,FProductTypeName,FBrandName,FOrganizationName,KOrganizationID,) FALLCount, end) SaleCou ...
- input 呼起数字键盘
1. Android,定义 type="number" 2. iOS,定义 style="ime-mode: disabled;" 注,呼起数字键盘后,用户输入 ...
- test001
#include <iostream> using namespace std; ][]; int main() { int num; ; ; i <= ; i++) dp[i][] ...
- linux c调用 mysql代码
代码: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <mysql/ ...
- 04Hadoop中的setPartitionerClass/SortComparator/GroupingComparator问题
map阶段 1. 使用job.setInputFormatClass(TextInputFormat)做为输入格式.注意输出应该符合自定义Map中定义的输出. 2. 进入Mapper的map()方法, ...
- error connecting: Timeout expired 超时时间已到. 达到了最大池大小 错误及Max Pool Size设置
[参考]Timeout expired 超时时间已到. 达到了最大池大小 错误及Max Pool Size设置 [参考][数据库-MySql] MySqlConnection error connec ...
- 配置python开发环境(Eclipse + pyDev)
jdk-11.0.2eclipse 2018-12python 3.7.2 1. install jdk, 配置环境变量 新建JAVA_HOME 系统变量,C:\Program Files\Java\ ...
- kafka---->kafka connect的使用(一)
这里面介绍一下kafka connect的一些使用. kafka connect的使用 一.在config目录下面复制一个file-srouce.properties并且修改内容 huhx@gohuh ...