工厂模式包含三种,简单工厂模式,工厂方法模式,抽象工厂模式。这三种都是解决了一个问题,那就是对象的创建问题。他们的职责就是将对象的创建和对象的使用分离开来。

当我们创建对象的时候,总是会new一个对象,有错么?技术上,new没有错,毕竟是C#的基础部分,真正的犯人是我们的老朋友“改变”。以及他是如何影响new使用的。

针对接口编程,可以隔离掉以后系统可能发生的一大堆改变,为什么呢?如果代码是针对接口而写,那么通过多态,他可以与任何新类实现该接口,但是,当代码使用大量的具体类时,一旦加入新的具体类,就必须改变代码。违反了开闭原则了。

简单工厂

我们先来看一下要订购一个披萨的方法:

public static Pizza OrderPizza(string pizzaType)
{
Pizza pizza;
switch (pizzaType)
{
case "cheese":
pizza= new CheesePizza();
break;
case "ApplePie":
pizza= new ApplePiePizza();
break;
default:
pizza=new SomeOtherPizza();
break;
}
pizza.Prepare();
pizza.Beak();
pizza.Cut();
pizza.Box();
return pizza;
}

如果让我来实现一个订购披萨的系统,我肯定会这么写代码,因为这种的代码是能下意识的就写出来,几乎不用耗费我们的脑筋。但是,仔细看一下这段代码:这个方法的目的是要订购披萨,但是,订购披萨的代码中还要有关于生产pizza的知识,这个方法必须要知道所有的pizza,更加糟糕的是,如果将来要扩充pizza的种类或者删减销量不好的pizza,那么就会来修改这个订购披萨的代码了。看起来很糟糕,应该修改一下。我们第一步要做的一定是要将生产pizza的代码和订购披萨的代码分开来,因为你不应该让订购pizza的代码知道如何生产披萨的逻辑,应该将生产pizza的逻辑单独交给一个专门的类型来负责。这样,就可以应对将来的变化——如果要新增或者删除pizza,我们可以直接修改pizza的生产者而不影响到订购pizza这个逻辑。

而专门生产pizza的这个对象,我们可以叫他为工厂。看一下实现的代码:

 public class SimpleFactory
{
public Pizza CreatePizza(string pizzaType)
{
switch (pizzaType)
{
case "cheese":
return new CheesePizza();
case "ApplePie":
return new ApplePiePizza();
default:
return new SomeOtherPizza();
}
}
}
 public class PizzaStore
{
private SimpleFactory _factory; public PizzaStore(SimpleFactory factory)
{
this._factory = factory;
}
public Pizza OrderPizza(string pizzaType)
{
var pizza = _factory.CreatePizza(pizzaType);
pizza.Prepare();
pizza.Beak();
pizza.Cut();
pizza.Box();
return pizza;
}
}

把创建对象的逻辑放到一个单独的类中的原因是它可以被多个客户端使用。并且把对象的创建和使用分离开来。但是这样的设计也存在很多缺陷,首先,SimpleFactory是一个具体的类,那么我们就必须针对实现编程,使得系统失去了这方面的弹性,二是如果增加新的产品我们还得修改simplefactory中的代码,这违反了开闭原则。上面这个模式也叫做简单工厂。他没有在GOF的模式中出现,它更像是一个编程的习惯。

可以看到PizzaStore依赖一个SImpleFactory,SimpleFactory依赖一个抽象的pizza。正常情况下,要做解耦,就要做控制反转,控制反转的核心思想是上层结构和底层结构都不依赖实现,而是依赖抽象。

工厂方法模式

现在来做一些改良,直接上代码:

 public abstract class FactoryPizzaStore
{
public Pizza OrderPizza(string pizzaType)
{
Pizza pizza = CreatePizza(pizzaType);
pizza .Prepare();
pizza.Beak();
pizza.Cut();
pizza.Box();
return pizza;
}
public abstract Pizza CreatePizza(string pizzaType);
}

现在,PizzaStrore(FactoryPizzaStore)是抽象的。CreatePizza方法从简单工厂移植回来了。在PizzaStroe里面,CreatePizza方法现在是抽象的。

现在已经有一个抽象的PizzaStore类,其他类可以从这个类进行扩展,并重写自己的CreatePizza方法。

解释一下,在OrderPizza方法中,我们做了很多事情,包括调用CreatePizza方法产生一个想要的pizza,然后对pizza进行一系列的操作,关键在于,Pizza被定义为一个抽象类,也就是说在OrderPizza方法中我们并不关心这个Pizza在运行时到底是一个什么类型,换句话说,这就是解耦。解除了PizzaStore和Pizza之间的耦合。

那么现在,原本是通过一个对象负责所有具体类的实例化,现在通过对PizzaStore做的一些改变,变成由一群子类来对具体类的实例化:FactoryPizzaStore的子类负责实现CreatePizza;

更进一步的:工厂方法用来处理对象的创建,并把这种创建对象的实现延迟到子类中去实现,这样,客户代码中关于基类的代码就和子类对象创建代码解耦了。

由于Pizza还是一个抽象类,当我们创建一个FactoryPizzaStore的子类的时候,也应该实现一个具体的继承自Pizza的子类,如果只创建一个FactoryPizzaStore的子类,而没有相对应的Pizza的子类,那么我们的披萨店卖什么呢?

 public abstract class Pizza
{
public string Name { get; set; }
public string Dough { get; set; }
public string Sauce { get; set; }
public List<string> Toopings { get; set; } public void Prepare()
{
Console.WriteLine($"Preparing {Name}");
Console.WriteLine("Tossing dough");
Console.WriteLine("Adding sauce");
Console.WriteLine("Adding Toppings..");
foreach (string item in Toopings)
{
Console.WriteLine($" {item}");
}
} public void Cut()
{
Console.WriteLine("Cutting the pizza..");
} public void Bake()
{
Console.WriteLine("Baking the pizza");
} public void Box()
{
Console.WriteLine("Boxing the pizza");
}
}

在创建一些Pizza的子类后,就可以开始测试了:

 static void Main(string[] args)
{
FactoryPizzaStore store=new NyPizzaStore();
var pizza = store.OrderPizza("Cheese");
Console.WriteLine(pizza.Name);
Console.ReadKey();
}

认识工厂方法模式:所有的工厂方法模式都是用来创建对象的。工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建过程进行封装的目的。工厂方法模式有如下几个角色:

1、创建者:就是上面定义的FactoryPizzaStore。它是一个抽象类,它定义了创建对象的方法,这个方法是一个抽象方法,具体的创建对象的过程由其子类来实现。这个抽象类通常会依赖一个抽象的产品(Product,工厂方法模式中的另一个角色)类。而这些抽象产品由子类制造,创建者并不关心制造的是哪种产品。

2、产品类:就是上面定义的Pizza,它也是一个抽象类,具体的产品由其子类来实现。

我们已经看到,将一个OrderPizza方法和一个工厂方法联合起来(就是FactoryPizzaStore里面的那两个方法),就形成了一个框架。除此之外,工厂方法吧生产知识封装到各个创建者子类,这也可以形成一个框架。

下面给出工厂方法的定义:定义了一个创建对象的接口,但由子类决定要具体创建哪一个。工厂方法让这种创建对象的过程推迟到子类。

简单工厂和工厂方法之间的差异:简单工厂和工厂方法模式看起来很相似,尤其是简单工厂和工厂方法中的具体工厂。简单工厂吧全部的事情,在一个地方都做完了。然而工厂方法创建的是一个框架,让子类决定如何实现。比方说,在工厂方法中,OrderPizza方法创建了一般的框架,以便创建披萨,OrderPizza方法依赖工厂方法创建具体的类,并制造出实际的披萨。可通过继承工厂,决定制造的实际产品到底是什么。简单工厂不具备这方面的弹性。

封装变化

将创建对象的代码封装起来,实例化具体的工厂类,达到了封装实例化目的。将创建对象的代码封装到一个地方,也可以达到复用的目的,并且更方便以后的维护。这也意味着客户在实例化对象时,只会依赖接口,不会依赖具体的实现。帮助我们更好的达到针对接口编程而不是实现,让代码更有弹性,以应对未来的扩展。

C#设计模式之5:简单工厂和工厂方法模式的更多相关文章

  1. NET设计模式 第二部分 行为型模式(15):模版方法模式(Template Method)

    摘要:Template Method模式是比较简单的设计模式之一,但它却是代码复用的一项基本的技术,在类库中尤其重要. 主要内容 1.概述 2.Template Method解说 3..NET中的Te ...

  2. Java设计模式2:简单工厂模式

    简单工厂模式 简单工厂模式是类的创建模式,又叫做静态工厂方法模式.简单工厂模式由一个工厂对象决定生产出哪一种产品类的实例. 为什么要使用简单工厂模式 原因很简单:解耦. A对象如果要调用B对象,最简单 ...

  3. 大话设计模式C++版——简单工厂模式

    简单工厂模式应该是所有设计模式中最简单,也最基础的一种模式,以下是一个简单的采用工厂模式写一个加减法的计算器. 1.抽象接口类——依赖倒转原则(高层和底层都要依赖于抽象,针对接口编程) class I ...

  4. IOS设计模式浅析之简单工厂模式(SimpleFactory)

    概述 首先说明一下,简单工厂模式不属于23种GOF设计模式之一.它也称作静态工厂方法模式,是工厂方法模式的特殊实现.这里对简单工厂模式进行介绍,是为本系列后面的工厂方法和抽象工厂模式做一个引子. 定义 ...

  5. 设计模式C#实现(九)——工厂方法模式和简单工厂

    工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类.Factory Method使一个类的实例化延迟到其子类. 构成: 1.Product工厂方法创建的对象的接口 2.Concrete ...

  6. Java设计模式之工厂模式(简单工厂模式+工厂方法模式)

    摘自http://blog.csdn.net/jason0539/article/details/23020989 在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是 ...

  7. Java设计模式之简单工厂、工厂方法和抽象工厂

    在前面的学习中(参见前面的博客),我们学到了很多OO原则: 封装变化 多用组合,少用继承 针对接口/超类编程,不针对实现编程 松耦合 开闭原则 让我们从一个简单的类开始,看看如何将之改造成符合OO原则 ...

  8. Java设计模式---工厂模式(简单工厂、工厂方法、抽象工厂)

    工厂模式:主要用来实例化有共同接口的类,工厂模式可以动态决定应该实例化那一个类.工厂模式的形态工厂模式主要用一下几种形态:1:简单工厂(Simple Factory).2:工厂方法(Factory M ...

  9. 设计模式--简单工厂VS工厂VS抽象工厂

    前几天我一直在准备大学毕业生,始终绑起来,如今,终于有时间去学习设计模式.我们研究今天的话题是植物三口之家的设计模式的控制--简单工厂VS工厂VS抽象工厂. 经过细心推敲,我们不难得出:工厂模式是简单 ...

  10. C#设计模式之二简单工厂模式(过渡模式)

    一.引言 之所以写这个系列,是了为了自己更好的理解设计模式,也为新手提供一些帮助,我都是用最简单的.最生活化的实例来说明.在上一篇文章中讲解了单例模式,今天就给大家讲一个比较简单的模式--简单工厂模式 ...

随机推荐

  1. 【JAVA8】双冒号

    现在JDK双冒号是: public class MyTest {     public static void  printValur(String str){         System.out. ...

  2. UVA12188-Inspector's Dilemma(欧拉回路+连通性判断)

    Problem UVA12188-Inspector's Dilemma Time Limit: 3000 mSec Problem Description In a country, there a ...

  3. 关于reduce的理解

    什么是reduce reduce这个词字面上来讲,大多称作“归约”,但这个词太专业了,以至于第一眼看不出来意思.我更倾向于解释为“塌缩”,这样就形象多了.对一个n维的情况进行reduce,就是将执行操 ...

  4. P1460 健康的荷斯坦奶牛 Healthy(DFS)

    思路:这道题还是用了小小的剪枝,这里要注意的是该题有很多中构建树的顺序,但是,在这众多顺序中不一定都能保证输出的方案字典序最小. 构建搜索树:如图构建 剪枝,emmm,看代码: #include< ...

  5. 钉钉自定义机器人 发送文本 换行 \n无效果

    今天用php做钉钉自定义机器人 发送文本 换行 \n无效果,原来是我一直用单引号作为定义字符串,换成双引号就ok了.

  6. Linux:Day2 发行版本、命令获取

    Linux的哲学思想: 1.一切皆文件:把几乎所有资源,包括硬件设备都组织为文件格式: 2.由众多单一目的的小程序组成,一个程序只实现一个功能,而且要做好: 组合小程序完成复杂任务: 3.尽量避免跟用 ...

  7. 用 virtualenv 创建隔离的 Python 运行环境

    以 Ubuntu 14.04 系统为例,安装的 Python 和 Python3 分别是 2.7.6 和 3.4.3, 但有些项目,有些模块要求特定的 Python 版本.而当前系统默认的 Pytho ...

  8. Generative Adversarial Nets[iGAN]

    本文来自<Generative Visual Manipulation on the Natural Image Manifold>,是大神Jun-Yan Zhu在2016年9月的作品. ...

  9. Python协程(真才实学,想学的进来)

    真正有知识的人的成长过程,就像麦穗的成长过程:麦穗空的时候,麦子长得很快,麦穗骄傲地高高昂起,但是,麦穗成熟饱满时,它们开始谦虚,垂下麦芒. --蒙田<蒙田随笔全集> *** 上篇论述了关 ...

  10. A2dp sink 初始化流程源码分析

    A2dp sink的初始化流程和A2dp 的初始化流程,基本一样,这里做简单分析.这里分析的android的版本是Android O. 我们先从service的启动说起吧. 下面 是启动的时候的log ...