[Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式
系列文章
[Head First设计模式]山西面馆中的设计模式——装饰者模式
[Head First设计模式]山西面馆中的设计模式——观察者模式
[Head First设计模式]山西面馆中的设计模式——建造者模式
引言
今天是冬至,去饺子馆吃饺子,看他们店里面的水饺种类挺多,在等待中,在想是不是可以用设计模式模拟一下,生产饺子的过程,正好最近也在看工厂模式,也就现学现卖了。当然,实现的方式很多,只是一个例子而已。祝大家冬至,多多吃水饺.....
对象创建的问题?
我们应该面向接口编程而不是面向实现编程,因为面向实现编程会使得我们的设计更脆弱,缺乏灵活性。但是我们每次使用new时,是不是正在违背这一设计原则呢?
当我们拥有一组相关的具体类时,是不是常常被迫写出类似下面的代码?
Duck duck; if(picnic){ duck=new MallardDuck(); }else if(hunting){ duck=new DecogDuck(); }else if(inBathTub){ duck=new RubberDuck(); }(以上为伪代码,只为说明问题)
向上面的实例化过程,知道运行时我们才知道需要实例化哪个类。
这样做的后果是如果应用要做变化或扩展,往往要修改这段代码。这使得维护困难,并容易引入错误。
问题在哪儿?
出现上面那种问题,是不是new的问题呢?
从技术上来说,new并没有任何问题。new只是面向对象语言的最基本部分,真正的问题在于“变化”。
如果对接口编程,我们可以实现与许多“变化”的隔离,因为通过多态机制,我们的代码对于实现接口的新类依然适用。但是使用具体类麻烦就来了,因为增加新的具体类时相应的代码可能就必须修改?
怎么办?
面向对象的设计原则:识别变化的部分,并将与不变化的部分相分离。
书中Pizza店案例分析
PizzaStore类中的一段代码-订做pizza

修改后的代码

由于市场竞争,其他pizza店推出了新产品,我们也得增加!例如VeggiePizza。 GreekPizza最近不受欢迎,把它从菜单中取消。
于是。。。

分析:变与不变的部分

分离

我们将专管制作pizza的对象叫做Pizza工厂

Pizza工厂---SimplePizzaFactory

思考一下?
这看来好像我们只是把问题从一个对象推给了另一个对象!这样做有什么好处?
SimplePizzaFactory可以有许多个客户,这样,当实现改变时我们只需要修改SimplePizzaFactory,而不需修改众多的客户。 提高了聚合度,PizzaStore的职责是使用pizza对象, SimplePizzaFactory的职责是决定创建什么样的pizza对象。
用工厂重写PizzaStore类
public class PizzaStore {
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) {
this.factory = factory;
}
public Pizza orderPizza(String type) {
Pizza pizza;
pizza=factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
//other methods here
}
简单工厂模式


饺子馆中的简单工厂实现
水饺要实现的接口
/// <summary>
/// 水饺要实现的接口
/// </summary>
public interface IDumpling
{
string DumplingName { get; }
/// <summary>
/// 水饺的准备阶段方法
/// </summary>
void Prepare();
/// <summary>
/// 煮
/// </summary>
void Boild();
/// <summary>
/// 展示订单
/// </summary>
void Show();
}
具体的水饺类
/// <summary>
/// 猪肉大葱水饺类
/// </summary>
public class PorkAndScallionDumpling:IDumpling
{ public string DumplingName
{
get { return "猪肉大葱水饺"; }
} public void Prepare()
{
Console.WriteLine("准备猪肉茴香水饺25个");
} public void Boild()
{
Console.WriteLine("正在煮......请稍等.....");
} public void Show()
{
Console.WriteLine("您的{0},准备好了。", this.DumplingName);
}
}
/// <summary>
/// 猪肉茴香水饺类
/// </summary>
public class PorkAndFennelDumpling : IDumpling
{
public string DumplingName
{
get { return "猪肉茴香水饺"; }
} public void Prepare()
{
Console.WriteLine("准备猪肉茴香水饺25个");
} public void Boild()
{
Console.WriteLine("正在煮......请稍等.....");
} public void Show()
{
Console.WriteLine("您的{0},准备好了。", this.DumplingName);
}
}
工厂类
/// <summary>
/// 水饺的生产工厂
/// </summary>
public static class SimpleDumplingFactory
{
public static IDumpling CreateDumpling(string dumplingName)
{
IDumpling dumpling = null;
switch (dumplingName)
{
case "猪肉大葱":
dumpling = new PorkAndScallionDumpling();
break;
case "猪肉茴香":
dumpling = new PorkAndFennelDumpling();
break;
}
return dumpling;
}
}
控制台代码
class Program
{
static void Main(string[] args)
{
IDumpling dumpling = SimpleDumplingFactory.CreateDumpling("猪肉茴香");
dumpling.Prepare();
dumpling.Boild();
dumpling.Show();
Console.Read();
}
}
结果
授权pizza店
我们的pizza店非常成功,许多人都想开设我们的授权加盟店。为保证质量,我们希望他们使用我们经过时间考验的代码。
但是,不同地区的加盟pizza店可能希望供应不同口味的pizza。怎么解决这个问题呢?
解决方法之一:建立不同的工厂
//建立不同的工厂:如NYPizzaFactory、 ChicagoPizzaFactory、 CaliforniaPizzaFactory,在PizzaStore中包含相应工厂的实例。其代码类似于:
//该pizza店提供纽约风味的pizza
NYPizzaFactory nyFactory=new NYPizzaFactory();//建立一个生产纽约风味pizza的工厂
PizzaStore nyStore=new PizzaStore(nyFactory);//建立一个pizza店,引用纽约风味pizza的工厂
nyStore.orderPizza(“Veggie”);//生产的是纽约风味的pizza //该pizza店提供芝加哥风味的pizza
ChicagoPizzaFactory chicagoFactory=new ChicagoPizzaFactory();
PizzaStore chicagoStore=new PizzaStore(chicagoFactory);
chicagoStore.orderPizza(“Veggie”);
抽象工厂模式
这么多工厂,可以再增加抽象层
另一种解决方法-工厂方法模式
思路:改写的PizzaStore,将createPizza()方法放回到PizzaStore,但是声明为抽象方法,然后,为每一种地方风味创建一个PizzaStore的子类。
改造后的PizzaStore的代码
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);//在PizzaStore内调用自身的一个方法来制造pizza,而不是使用一个factory对象
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
abstract Pizza createPizza(String type);//factory对象成了这里的一个抽象方法
}
下面我们需要PizzaStore的各种子类(对应不同的地区风味)
让子类做决定

声明工厂方法
abstract Pizza createPizza(String type);
abstract Product factoryMethod(String type);
工厂方法是抽象的,在一个超类中定义。必须由子类来实现。
工厂方法返回一个产品,该产品通常在其所在类的方法中定义。(如orderPizza())
工厂方法通常提供参数,用以选择一个产品的不同品种。
工厂方法将客户(超类中的方法,如PizzaStore中的orderPizza())与具体的产品相隔离。
工厂方法怎么工作?
假定张三喜欢纽约风味的pizza,李四喜欢芝加哥风味的pizza。
需要相应Pizza店的实例
调用orderPizza()订购想要的pizza品种
createPizza()被调用,并返回pizza到orderPizza()方法。
尽管不知道是什么pizza,但orderPizza()仍知道对它进行后续处理。
工厂方法模式中的类
创建者类 The Creator classes

产品类 The Product classes

工厂方法模式的定义
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式让一个类的实例化延迟到其子类。
工厂方法模式的结构

总结:Factory Method模式
意图
定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式让一个类的实例化延迟到其子类。
别名
虚拟构造器
Factory Method—参与者
Product(document)定义工厂方法所创建对象的接口。
ConcreteProduct(mydocument)实现product接口。
Creator(application)声明工厂方法,可以调用工厂方法以创建一个product对象
ConcreteCreator (MyApplication)重新定义工厂方法,以返回一个ConcreteProduct实例
(篇幅有点长,关于工厂方法模式的实例就不再列举了,感兴趣的可以自己实现一下)
参考书:
《First Head 设计模式》
[Head First设计模式]饺子馆(冬至)中的设计模式——工厂模式的更多相关文章
- 在商城系统中使用设计模式----简单工厂模式之在springboot中使用简单工厂模式
1.前言: 不了解简单工厂模式请先移步:在商城中使用简单工厂.在这里主要是对springboot中使用简单工厂模式进行解析. 2.问题: 什么是简单工厂:它的实现方式是由一个工厂类根据传入的参数,动态 ...
- Spring中如何使用工厂模式实现程序解耦?
目录 1. 啥是耦合.解耦? 2. jdbc程序进行解耦 3.传统dao.service.controller的程序耦合性 4.使用工厂模式实现解耦 5.工厂模式改进 6.结语 @ 1. 啥是耦合.解 ...
- Java中的简单工厂模式
举两个例子以快速明白Java中的简单 工厂模式: 女娲抟土造人话说:“天地开辟,未有人民,女娲抟土为人.”女娲需要用土造出一个个的人,但在女娲造出人之前,人的概念只存在于女娲的思想里面.女娲造人,这就 ...
- Java中的简单工厂模式(转)
Java中的简单工厂模式 举两个例子以快速明白Java中的简单工厂模式: 女娲抟土造人话说:“天地开辟,未有人民,女娲抟土为人.”女娲需要用土造出一个个的人,但在女娲造出人之前,人的概念只存在于女娲的 ...
- 初探Java设计模式4:JDK中的设计模式
JDK中设计模式 本文主要是归纳了JDK中所包含的设计模式,包括作用和其设计类图.首先来个总结,具体的某个模式可以一个一个慢慢写,希望能对研究JDK和设计模式有所帮助.一.设计模式是什么(1)反复出现 ...
- OOP设计模式在路上(一)——简单工厂模式
前言 目前以LabVIEW为主要开发工具,熟悉常规开发框架(队列+状态机),个人用得比较多也感觉比较好用和强大的(JKI,AMC),也用它们开发过一些测试平台,但感觉到了一个瓶颈期,想寻求突破,提升L ...
- 大话设计模式C++实现-第1章-简单工厂模式
一.UML图 二.包括的角色 简单工厂模式包括三个角色: (1)工厂类Factory:工厂类是用来制造产品的. 因此,在Factory中有一个用于制造产品的Create函数或者Generate函数之类 ...
- JAVA设计模式(01):创建型-工厂模式【工厂方法模式】(Factory Method)
简单工厂模式尽管简单,但存在一个非常严重的问题.当系统中须要引入新产品时,因为静态工厂方法通过所传入參数的不同来创建不同的产品,这必然要改动工厂类的源码,将违背"开闭原则".怎样实 ...
- PHP中单例模式与工厂模式
单例模式概念 单例模式是指整个应用中类只有一个对象实例的设计模式. 单例模式的特点 一个类在整个应用中只有一个实例 类必须自行创建这个实例 必须自行向整个系统提供这个实例 php中使用单例模式的原因 ...
随机推荐
- android android 判断是否滑动
(转自:http://blog.csdn.net/angle_rupert/article/details/6255522) 声明: float x_temp01 = 0.0f; float y_te ...
- 详解Python中的循环语句的用法
一.简介 Python的条件和循环语句,决定了程序的控制流程,体现结构的多样性.须重要理解,if.while.for以及与它们相搭配的 else. elif.break.continue和pass语句 ...
- ipv4理论知识1-ipv4介绍,ipv4记法,地址段个数算法
定义 在TCP/IP协议中,用于在IP层识别连接到因特网设备的标识符称为因特网地址或IP地址.IPv4地址是一个32位的地址. 地址空间 像IPv4这种定义了地址的协议都有一个地址空间.地址空间就是协 ...
- 【小白的CFD之旅】06 流体力学基础
从黄师姐那里了解到要学习CFD的话,需要先补充流体力学.数学以及计算机方面的常识,小白就一阵头大.想起当初自己已经把牛皮吹出去了,现在都不知道怎么收场,一个月入不了门多丢人.不过头大归头大,小白还是老 ...
- 数据分析:.Net程序员该如何选择?
上文我介绍了用.Net实现的拉勾爬虫,可全站采集,其中.Net和C#(不区分)的数据爬取开始的早,全国主要城市都有一定数量的分布,加上有了近期其他相似技术类别的数据进行横向比较,可以得到比较合理的推测 ...
- XML介绍
XML [TOC] 1.XML简介 XML是Extend Markup Langue可扩展标签语言,标签由开发着自己定义 作用是: 1.描述带关系的数据(作为软件的配置文件):包含与被包含的关系 2. ...
- <<MySchool数据库设计优化>> 内部测试
1) 在SQL Server 中,为数据库表建立索引能够( C ). A. 防止非法的删除操作 B. 防止非法的插入操作 C. 提高查询性能 D. 节约数据库的磁盘空间 解析:索引的作用是通过使用索引 ...
- 前端之html
前端之html 本节内容 前端概述 html结构 标签探秘 <!DOCTYPE html>标签 head标签 body标签 1.前端概述 一个web服务的组成分为前端和后端部分,前端部分负 ...
- ThreadLocal实现方式&使用介绍—无锁化线程封闭
原文出处: xieyu_zy 虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以 ...
- Centos6安装Gitlab
安装参考 https://about.gitlab.com/downloads/ 可以从清华的镜像下载安装包, 注意区分自己用的是哪个发行版 https://mirror.tuna.tsinghua. ...