前言:按照惯例我以Head First设计模式的工厂模式例子开始编码学习。并由简单工厂,工厂模式,抽象工厂模式依次演变,归纳他们的相同与不同。

话说Head First认为简单工厂并不是设计模式,而是一种编程习惯,但并不妨碍我们使用它,接下来我们对工厂模式一探究竟。

1、披萨店例子

首先我们要开一个披萨店,对于业务不复杂的情况下我们可以快速的开发出一个披萨店以及订购披萨的逻辑

    public Pizza OrderPizza() {
Pizza pizza = new Pizza(); pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
} public class Pizza {
//准备
public void Prepare() { }
//烘烤
public void Bake() { }
//切片
public void Cut() { }
//装盒
public void Box() { }
}

如果我们有更多的披萨种类可能需要将Pizza定义成抽象类 在订单里面根据订购的披萨种类返回不同的披萨,我们对披萨进行抽象并改造Order。

    public class PizzaStore
{
public Pizza OrderPizza(string type)
{
Pizza pizza=null;
if (type == "cheese")
{
pizza = new CheesePizza();
}
else if (type == "viggie") {
pizza = new VeggiePizza();
}
//else if ......
pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
} public abstract class Pizza
{
//准备
public void Prepare() { }
//烘烤
public void Bake() { }
//切片
public void Cut() { }
//装盒
public void Box() { }
} //奶酪披萨
public class CheesePizza : Pizza
{
}
//素食披萨
public class VeggiePizza : Pizza
{
}

到这里我们可能想到了,如果增加披萨种类或者移除披萨那么我们将对披萨店进行修改。

设计原则对扩展开放,对修改关闭。我们需要将创建披萨的变化封装起来。对此弄出来一个专门创建披萨的“工厂“类。

并采用静态,这样就不需要实例化对象,也遵循了不对实现编程原则。

 public class PizzaStore
{
public Pizza OrderPizza(string type)
{
Pizza pizza = SimplePizzaFactory.CreatePizza(type); pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
}
} public static class SimplePizzaFactory {
public static Pizza CreatePizza(string type) {
Pizza pizza = null;
if (type == "cheese")
{
pizza = new CheesePizza();
}
else if (type == "viggie")
{
pizza = new VeggiePizza();
}
return pizza;
}
}

  这样将创建披萨简单的封装起来即是简单工厂(静态工厂),简单工厂也可以不用静态类,但简单工厂并不是一种专门的设计模式(有时候可能会混淆,认为这即是”工厂模式“),更像是我们平时编程都会做的一种习惯。我们将改动封装在一个局部当有变化的时候只需要修改这个工厂类。

2、更多的披萨店

现在我们要开更多的披萨店,例如美国风格披萨店(USSytlePizzaStore)、中国风格披萨店(CHNSytlePizzaStore)。

我们可以采用简单工厂模式,创建两个不同风格的披萨工厂,然后创建两个不同风格的披萨店,不同风格的披萨店使用对应的披萨工厂来获取。

但是我们此时的变化点是披萨店。我们希望披萨店的结构或者流程是按照一定规则的,只是不同风格的披萨。此时我们有更好的解决办法:工厂模式。

接下来我们看如何实现

    public abstract class PizzaStore
{
public Pizza OrderPizza(string type)
{
Pizza pizza= CreatePizza(type); pizza.Prepare();
pizza.Bake();
pizza.Cut();
pizza.Box();
return pizza;
} public abstract Pizza CreatePizza(string type);
} public class USSytlePizzaStore : PizzaStore
{
public override Pizza CreatePizza(string type)
{
Pizza pizza = null;
if (type == "cheese")
{
pizza = new USStyleCheesePizza();
}
else if (type == "viggie")
{
pizza = new USStyleVeggiePizza();
}
return pizza;
}
} public class CHNSytlePizzaStore : PizzaStore
{
public override Pizza CreatePizza(string type)
{
Pizza pizza = null;
if (type == "cheese")
{
pizza = new CHNStyleCheesePizza();
}
else if (type == "viggie")
{
pizza = new CHNStyleVeggiePizza();
}
return pizza;
}
} //US奶酪披萨
public class USStyleCheesePizza : Pizza
{
}
//US素食披萨
public class USStyleVeggiePizza : Pizza
{
} //CHN奶酪披萨
public class CHNStyleCheesePizza : Pizza
{
}
//CHN素食披萨
public class CHNStyleVeggiePizza : Pizza
{
}

由实现我们可以看到我们将PizzaStore修改成抽象类,不同的披萨店继承抽象类返回自己不同风格的披萨。

这样设计后当增加产品,我们也只是在具体的子类披萨店中修改其中的披萨创建,不会影响披萨店本身流程和其他披萨店的实现。

工厂方法模式:定义了一个创建对象的接口,由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。

工厂方法与简单工厂的区别:工厂方法的子类看起来很像简单工厂。简单工厂把全部的事情在一个地方处理完成,而工厂方法却是创建一个框架,让子类决定如何实现。

3、披萨的不同原料

不同风格的披萨店有不同风格的披萨,而这些披萨的不同风格是来自不同原料造成,所以不同风格的披萨变化的部分是材料。

我们先建造原料和原料工厂,以中国披萨原料工厂为例

//披萨原料工厂接口
public interface PizzaIngredientFactory {
public Veggie CreateVeggie();
public Cheese CreateCheese();
}
//具体工厂实现
public class CNHPizzaIngredientFactory : PizzaIngredientFactory
{
public Cheese CreateCheese()
{
return new CHNCheese();
} public Veggie CreateVeggie()
{
return new CHNVeggie();
}
} public abstract class Veggie
{
}
public class USVeggie : Veggie {
}
public class CHNVeggie : Veggie {
} public abstract class Cheese
{
}
public class USCheese : Cheese
{
}
public class CHNCheese : Cheese
{
}

  

  然后重做Pizza

    public abstract class Pizza
{
public String Name;
Veggie veggie;
Cheese cheese;
//准备
public abstract void Prepare();
//烘烤
public void Bake() { }
//切片
public void Cut() { }
//装盒
public void Box() { }
}

  加入了原料的抽象 Veggie 和 Cheese,同时我们让Prepare变成抽象方法,让他的具体子类决定用什么材制造不同风格的披萨。接着我们重做子类,以CheesePizza为例

    //奶酪披萨
public class CheesePizza : Pizza
{
PizzaIngredientFactory IngredientFactory;
public CheesePizza(PizzaIngredientFactory IngredientFactory) {
this.IngredientFactory = IngredientFactory;
}
public override void Prepare()
{
IngredientFactory.CreateCheese();
}
}

  修改中国披萨店

     public class CHNSytlePizzaStore : PizzaStore
{
public override Pizza CreatePizza(string type)
{
Pizza pizza = null;
//创建中国原材料工厂
CNHPizzaIngredientFactory ingredientFactory = new CNHPizzaIngredientFactory();
if (type == "cheese")
{
pizza = new CheesePizza(ingredientFactory);
}
else if (type == "viggie")
{
pizza = new VeggiePizza(ingredientFactory);
}
return pizza;
}
}

  

通过这一系列的改造我们引入了新类型的工厂,也就是所谓的抽象工厂,抽象工厂用来创造原料。

利用抽象工厂我们代码将从实际工厂解耦,这样如果我们的工厂需要扩展那么我们则可在子类中进行修改扩展。

工厂方法与抽象工厂的异同优缺点

相同:都是用来创建对象。

不同:工厂方法使用的是继承,抽象工厂使用的是组合。

优点:工厂方法只负责从具体类型中解耦,抽象工厂适合将一群相关的产品集合起来。

缺点:抽象工厂扩展接口需要修改每个子类。

Head First设计模式——简单工厂、工厂、抽象工厂的更多相关文章

  1. Java设计模式之-----工厂模式(简单工厂,抽象工厂)

    一.工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式在<Java与模式>中分为三类:1)简单工厂模式(Simple Factor ...

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

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

  3. Java设计模式(三) 抽象工厂模式

    原创文章,同步发自作者个人博客,转载请注明出处 http://www.jasongj.com/design_pattern/abstract_factory/ 抽象工厂模式解决的问题 上文<工厂 ...

  4. PHP设计模式(三)抽象工厂模式(Abstract Factory)

    一.什么是抽象工厂模式 抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象 ,而且使用抽象工厂模式还要满足以下条件: 系统中有多个产品族,而系统一次只可能消费其中一族产品. 同 ...

  5. Java设计模式学习笔记(四) 抽象工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 1. 抽象工厂模式概述 工厂方法模式通过引入工厂等级结构,解决了简单工厂模式中工厂类职责太重的问 ...

  6. &lt;十一&gt;读&lt;&lt;大话设计模式&gt;&gt;之抽象工厂模式

    学习设计模式有一段时间了,对设计模式有一个体会,就是没那么难.就是设计程序遵循一些原则,让代码可复用,在改动的时候不用涉及太多的类,扩展方便.抽象工厂模式名字听起来抽象.但理解起来一点也不抽象,用语言 ...

  7. Java的设计模式(4)--抽象工厂模式

    提供一个创建一系列或相互依赖对象的接口,而无须指定他们具体的类.例如某些系统可能需要为用户提供一系列相关对象,但系统不希望用户直接使用new运算符实例化这些对象,而是应当由系统来控制这些对象的创建,否 ...

  8. 详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂) v阅读目录

    1楼留头头大神:http://www.cnblogs.com/toutou/p/4899388.html   v阅读目录 v写在前面 v简单工厂模式 v工厂方法模式 v抽象工厂模式 v博客总结 v博客 ...

  9. Head First 设计模式 --4 工厂模式 抽象工厂模式

    (用到了依赖倒置原则) 我们写的代码中,有的时候可能会出现根据外面给定的不同的参数在方法中根据参数实例化不同的实例,就是会根据不同的参数会new出不同的实例.如果这么写了,这段代码会非常的脆弱,一旦出 ...

随机推荐

  1. JS/Jquery关系

    1. JS / JQuery介绍 Jquery是JS库,何为JS库,即把常用的js方法进行封装,封装到单独的JS文件中,要用的时候直接调用即可: 2. JS / JQuery对象 1. 定义 (1) ...

  2. IPv6系列-彻底弄明白有状态与无状态配置IPv6地址

    深入研究自动分配IPv6地址的Stateless(无状态)与Stateful(有状态)方式 小慢哥的原创文章,欢迎转载 目录 ▪ 一. Link-Local Address的生成方式 ▪ 二. Glo ...

  3. .net core 3.0 Signalr - 实现一个业务推送系统

    ## 介绍 ASP.NET Core SignalR 是一个开源代码库,它简化了向应用添加实时 Web 功能的过程. 实时 Web 功能使服务器端代码能够即时将内容推送到客户端. SignalR 的适 ...

  4. gym101666题解

    A Amsterdam Distance 题意 求圆环上的两点距离. 分析 显然是沿半径方向走到内圈再走圆弧最短. 代码 #include <bits/stdc++.h> using na ...

  5. .Net Core 微服务容器系列基础目录篇

    1.开场白 HI,各位老铁,大家端午好,之前写了些关于.net core商城系列的文章,有点乱,今天心血来潮想着整理一下(今天只是先把目录列出来,后面的每篇文章这两天会进行重新修改的,目前先将就看下) ...

  6. Windows定时备份Mysql数据库

    1.新建批处理文件bat(随意命名:如auto_backup_mysql_data.bat) 2.在批处理文件里添加如下命令 %1 mshta vbscript:createobject(" ...

  7. linux shell 统计当前目录下的文件个数

    shell 统计当前目录下文件个数,使用管道组合命令: ls -1 | wc -l 解释: ls -1 表示一行一个列出文件名. wc -l 表示打印统计的行数. 两个命令通过管道连在一起表示打印列出 ...

  8. 利用双重检查锁定和CAS算法:解决并发下数据库的一致性问题

    背景 ​ 最近有一个场景遇到了数据库的并发问题.现在先由我来抽象一下,去掉不必要的繁杂业务. ​ 数据库表book存储着每本书的阅读量,一开始数据库是空的,不存在任何的数据.当用户访问接口的时候,判断 ...

  9. CentOS7 Redis5.0.5环境搭建

    CentOS7 Redis5.0.5环境搭建 1基本环境配置 CentOS Linux release 7.6.1810 (Core) redis 5.0.5 1.下载解压redis.通过wget在官 ...

  10. 电信资源管理系统:基于 H5 叠加 OpenLayers3 GIS

    前言 通过结合 HTML5 和 OpenLayers 可以组合成非常棒的一个电信地图网络拓扑图的应用,形成的效果可以用来作为电信资源管理系统,美食定位分享软件,片区找房,绘制铁轨线路等等,各个领域都能 ...