设计模式之工厂方法(FactoryMethod)模式
在五大设计原则的基础上经过GOF(四人组)的总结,得出了23种经典设计模式,其中分为三大类:创建型(5种)、结构型(7种)、行为型(11种)。今天对创建型中的工厂方法(FactoryMethod)模式的思想进行了一下复习和实践,在此也做一下记录。同样,理解或实践不到位的地方,希望走过路过的看官指正一下!
同样先来看看工厂方法(FactoryMethod)模式的定义:
Define an interface for creating an object, but let subclasses decide which class to instantiate.
意思就是说:定义一个用于创建对象的接口,但让子类决定要实例化哪个类。
也就是工厂方法(FactoryMethod)模式允许将产品类的实例化推迟到具体的创建者子类,由创建者子类决定实例化哪一个产品类。我们同样以汽车的生产作为讲解该模式的例子,因为汽车生产从宏观上来说也是特别符合这个模式的。我要一辆汽车,什么品牌的我没有要求,符合是汽车这个标准就行了。那么世面上不同的汽车生产商就会用自己的生产流程生产出符合汽车这个标准的不同品牌汽车。同样,我们也撸起袖子码一码!因为该模式没有强调待生产的产品类是复杂的,同样也为了减少大家的代码阅读,这次我们把汽车相关类定义的更简单一点!
由于是让子类决定要实例化哪个产品类,那么高层的类或客户代码肯定是不需要知道有哪些具体产品类的,也就是得为众多具体的产品类制定一个产品标准(可以是接口,也可以是抽象类),这里我们定义一个汽车接口——ICar,它只有一个启动接口方法:
/// <summary>
/// 汽车接口
/// </summary>
public interface ICar
{
/// <summary>
/// 启动汽车
/// </summary>
/// <returns>是否启动成功</returns>
bool Start();
}
有了汽车产品标准(ICar),我们在此基础上定义两个实现了该标准的具有汽车产品类——奔驰(Benz)和宝马(BWM),它们对汽车产品标准中的启动标准做了不一样的实现(机械钥匙启动和按键启动):
/// <summary>
/// 奔驰汽车
/// </summary>
[Serializable]
public class BenzCar : ICar
{
private readonly string name = "Benz";
private readonly string model;
/// <summary>
/// 车名
/// </summary>
public string Name
{
get { return name; }
}
/// <summary>
/// 型号
/// </summary>
public string Model
{
get { return model; }
}
/// <summary>
/// 初始化奔驰汽车
/// </summary>
public BenzCar() { }
/// <summary>
/// 初始化奔驰汽车(带简单参数)
/// </summary>
/// <param name="model"></param>
public BenzCar(string model)
{
this.model = model;
}
/// <summary>
/// 启动奔驰汽车
/// </summary>
/// <returns>是否启动成功</returns>
public bool Start()
{
Console.WriteLine("【{0} {1}】通过机械钥匙启动!", Name, Model);
return true;
}
} /// <summary>
/// 宝马汽车
/// </summary>
[Serializable]
public class BwmCar : ICar
{
private readonly string name = "BWM";
private readonly string model;
/// <summary>
/// 车名
/// </summary>
public string Name
{
get { return name; }
}
/// <summary>
/// 型号
/// </summary>
public string Model
{
get { return model; }
} /// <summary>
/// 初始化宝马汽车
/// </summary>
public BwmCar() { }
/// <summary>
/// 初始化宝马汽车(带简单参数)
/// </summary>
/// <param name="model"></param>
public BwmCar(string model)
{
this.model = model;
}
/// <summary>
/// 启动宝马汽车
/// </summary>
/// <returns>是否启动成功</returns>
public bool Start()
{
Console.WriteLine("【{0} {1}】通过按键启动!", Name, Model);
return true;
}
}
有了汽车产品标准,也有了两个具体的汽车产品类型,生产商还没有,生产标准也还没有!回顾下工厂方法模式的定义:定义一个用于创建对象的接口,但让子类决定要实例化哪个类!这里的“用于创建对象的接口”其实就是生产标准,而“子类”就是实现了生产标准的具体生产商。在我们的例子中就是汽车生产者接口(标准)和实现了该标准的具体汽车生产商:
/// <summary>
/// 汽车生产接口(标准、规范)
/// </summary>
public interface ICarCreator
{
/// <summary>
/// 工厂级别的汽车生产接口方法(工厂方法模式的精髓所在!)
/// </summary>
/// <returns>生产好的汽车</returns>
ICar ProduceCar();
} /// <summary>
/// 奔驰生产者
/// </summary>
public class BenzCreator : ICarCreator
{
/// <summary>
/// 奔驰生产方法(对生产过程只做了简单模拟)
/// </summary>
/// <returns>奔驰汽车</returns>
public ICar ProduceCar()
{
ICar car = new BenzCar("梅赛德斯-AMG GLC 43 4MATIC");
Console.WriteLine("【Benz 梅赛德斯-AMG GLC 43 4MATIC】生产开始:\r1、生产发动机;\r2、生产底盘;\r3、生产车身;\r4、生产变速箱;\r5、生产轮胎;\r6、组装;");
Console.WriteLine("【Benz 梅赛德斯-AMG GLC 43 4MATIC】生产完成!");
return car;
}
} /// <summary>
/// 宝马生产者
/// </summary>
public class BwmCreator : ICarCreator
{
/// <summary>
/// 宝马生产方法(对生产过程只做了简单模似)
/// </summary>
/// <returns>宝马汽车</returns>
public ICar ProduceCar()
{
ICar car = new BwmCar("X7");
Console.WriteLine("【BWM X7】生产开始:\r1、生产底盘;\r2、生产发动机;\r3、生产变速箱;\r4、生产车身;\r5、生产轮胎;\r6、组装;");
Console.WriteLine("【BWM X7】生产完成!");
return car;
}
}
我们可以看到,对于汽车生产标准,实现了该标准的不同汽车生产者可以自行决定生产什么类型的汽车产品以及如何生产——让子类决定要实例化哪个类!
到目前为止,工厂方法(FactoryMethod)模式中各个角色都已经出现:用于创建对象的接口——汽车生产者接口(ICarCreator);子类(即具体的创建者)——奔驰生产者(BenzCreator)和宝马生产者(BwmCreator);要实例化的类(产品对象)——遵循统一产品标准(ICar)的奔驰汽车(BenzCar)和宝马汽车(BwmCar)。
接下来我们来测试一下这样的对象创建构造符不符合工厂方法(FactoryMethod)模式的定义:定义一个用于创建对象的接口,但让子类决定要实例化哪个类。
[TestClass]
public class FactoryMethodTest
{
[TestMethod]
public void TestFactoryMethod()
{
ICarCreator carCreator = new BenzCreator();//先将汽车创建者指向奔驰(Benz)汽车的创建者
ICar car = carCreator.ProduceCar();//由奔驰(Benz)汽车创建者决定生产什么车(实例化哪个类)
Assert.IsTrue(car.Start()); Console.Write("\r\r"); carCreator = new BwmCreator();//再将汽车创建者指向宝马(BWM)汽车的创建者
car = carCreator.ProduceCar();//再由宝马(BWM)汽车创建者决定生产什么车(实例化哪个类)
Assert.IsTrue(car.Start());
}
}
可以看到客户代码已经可以让子类决定要实例化哪个类。我们最后来看看测试输出结果:
最后,再次注意一下工厂方法(FactoryMethod)模式和构建者(Builder)模式的区别:
- 对要生产的产品制定了产品标准(IProduct),构建者模式中这个并不是必要的,当然也可以制定;
- 产品创建者标准(ICreator)只提供一个粗粒度的标准产品生产接口(FactoryMethod);
- 没有了额外的生产指导者,产品的具体创建流程和细节由具体的产品创建者(ConcreteCreator)自己决定;
工厂方法(FactoryMethod)模式的使用场景在于模式定义的后半句:让子类决定要实例化哪个类(子类是指创建者子类)。也就是当你在开发过程中,对于创建对象有这样的需求时可以考虑一下工厂方法模式!而构建者模式主要使用场景在于用相同的构建过程构建复杂对象的不同表示。
设计模式之工厂方法(FactoryMethod)模式的更多相关文章
- 一天一个设计模式——工厂方法(FactoryMethod)模式
一.模式说明 在前一个模板方法(Template Method)模式中,父类定义了处理流程,而流程中用到的方法交给子类去实现.类似的,在工厂方法模式中,父类决定如何生成实例,但并不决定所要生成的具体类 ...
- 【设计模式】——工厂方法FactoryMethod
前言:[模式总览]——————————by xingoo 模式意图 工厂方法在MVC中应用的很广泛. 工厂方法意在分离产品与创建的两个层次,使用户在一个工厂池中可以选择自己想要使用的产品,而忽略其创建 ...
- 工厂方法(FactoryMethod)模式
之前说了简单工厂设计模式如果增加一个新的运算的时候需要:增加一个具体的实现类,工厂类中增加一个case分支.也就是说我们不但对扩展开发了,也对修改开放了,违背了开闭原则.当然如果工厂类采用反射的话不存 ...
- 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern)
原文:乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pa ...
- 设计模式——从工厂方法模式到 IOC/DI思想
回顾简单工厂 回顾:从接口的角度去理解简单工厂模式 前面说到了简单工厂的本质是选择实现,说白了是由一个专门的类去负责生产我们所需要的对象,从而将对象的创建从代码中剥离出来,实现松耦合.我们来看一个例子 ...
- C#设计模式(3)——工厂方法模式
一.概念:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类. 二.代码实现 namespace 设计模式之工厂方法模式 { /// <summary&g ...
- C#设计模式(3)——工厂方法模式(转)
C#设计模式(3)——工厂方法模式 一.引言 在简单工厂模式中讲到简单工厂模式的缺点,有一点是——简单工厂模式系统难以扩展,一旦添加新产品就不得不修改简单工厂方法,这样就会造成简单工厂的实现逻辑过 ...
- Java设计模式之工厂方法模式(转) 实现是抽象工厂?
Java设计模式之工厂方法模式 责任编辑:覃里作者:Java研究组织 2009-02-25 来源:IT168网站 文本Tag: 设计模式 Java [IT168 技术文章] ...
- php设计模式之工厂方法模式
php设计模式之工厂方法模式 工厂方法模式 工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Pol ...
随机推荐
- python使用httplib2访问REST服务的例子
首先你需要安装httplib2,这个可以在github上找到: 然后你需要获得一个http连接的对象: con = httplib2.Http() 然后你需要发起连接: (6)resp, (5)c ...
- <string.h>的学习
感觉学习代码库最好的方法就是运行一下. 下面附上结果和示例代码 #include <stdio.h> #include <string.h> int main(){ const ...
- Git清空历史,清空历史删除的文件,降低.git 文件大小
执行以下步骤之前 请做好源码备份 本操作用来清理github上面的历史删除文件,减少库的体积. 第一步骤 下载JDK环境和JAR包 https://rtyley.github.io/bfg-repo- ...
- 【vue】项目编译报错‘npm ERR! **@**dev: `webpack-dev-server --inline --progress --config ’’
关于npm ERR! **@**dev: `webpack-dev-server --inline --progress --config‘ 原因:这是新版webpack存在的BUG,卸载现有的新版本 ...
- AngularJs自定义过滤器filter
AngularJs自带有很多过滤器,现在Insus.NET演示一个自定义的过滤器,如实现一个数据的平方. 本演示是在ASP.NET MVC环境中进行. 创建一个app: 创建一个控制器: 接下来是重点 ...
- 「PKUSC2018」真实排名(排列组合,数学)
前言 为什么随机跳题会跳到这种题目啊? Solution 我们发现可以把这个东西分情况讨论: 1.这个点没有加倍 这一段相同的可以看成一个点,然后后面的都可以. 这一段看成一个点,然后前面的不能对他造 ...
- #loj3090 [BJOI2019] 勘破神机
简单线性代数练习题 首先翻开具体数学生成函数一章,可以发现\(F(n),G(n)\)满足以下递推式 \[F(n)=F(n-1)+F(n-2),F(0)=1,F(1)=1\] \[G(n)=4G(n-2 ...
- Bash/Shell-脚本整理(长期更新)
轮询检测Apache状态并启用钉钉报警 #!/bin/bash shell_user="root" shell_domain="apache" shell_li ...
- web端权限维持【好文】
前言 关于权限维持,我之前写过一篇基于系统端的后门技术文章,如映像劫持啊,lpk之类. 内容目录: - 构造文件包含漏洞- 隐蔽性脚本木马- 构造sql注入点 正文 0x01 构造文件包含漏洞 > ...
- C#导出HTML到PDF组件 Pechkin
C#导出PDF功能是开发中经常遇到的功能,我们采用第三方的组件,比如 iTextSharp, aspose等,还能搜到一些开源的类库, 但是对于一些内容复杂样式丰富的PDF,我们希望通过传入一个URL ...