工厂模式是最常用的一种创建型模式,通常所说的工厂模式一般是指工厂方法模式。本篇是是工厂方法模式的“小弟”,我们可以将其理解为工厂方法模式的预备知识,它不属于GoF 23种设计模式,但在软件开发中却也应用地比较频繁。此外,工厂方法模式还有一位“大哥”—抽象工厂模式,会在后面进行介绍。

简单工厂模式(Simple Factory)
学习难度:★★☆☆☆
使用频率:★★★☆☆

一、从一个图表库谈起

  M公司想要基于C#语言开发一套图表库,该图表库可以为应用系统提供各种不同外观的图标,例如柱状图、饼状图或折线图等。M公司图表库设计开发人员希望为应用系统开发人员提供一套灵活易用的图表库,而且可以较为方便地对图表库进行扩展,以便于在将来增加一些新类型的图表。

  M公司的程序员提出了一个初始设计方案,将所有图表的实现代码封装在一个Chart类中,其框架代码如下所示:

public class Chart
    {
        private string type; // 图表类型
 
        public Chart(object[][] data, string type)
        {
            this.type = type;
            switch (type.ToLowerInvariant())
            {
                case "histogram":
                    {
                        // 初始化柱状图
                        break;
                    }
                case "pie":
                    {
                        // 初始化饼状图
                        break;
                    }
                case "line":
                    {
                        // 初始化折线图
                        break;
                    }
            }
        }
 
        public void Display()
        {
            switch (type.ToLowerInvariant())
            {
                case "histogram":
                    {
                        // 显示柱状图
                        break;
                    }
                case "pie":
                    {
                        // 显示饼状图
                        break;
                    }
                case "line":
                    {
                        // 显示折线图
                        break;
                    }
            }
        }
    }

修改点:多个if-else 判断不太好,可以用switch更好些

  客户端代码通过调用Chart类的构造函数来创建图表对象,根据参数type的不同可以得到不同类型的图标,然后再调用Display()方法来显示相应的图表。

  但是,不难看出,Chart类是一个巨大的类,存在很多问题:

  • 在Chart类中包含很多if-else代码块,相当冗长,可读性很差;
  • Chart类的职责过重,负责初始化和显示各种图表对象,违反了单一职责原则;
  • 当需要增加新的图表类型时,必须修改Chart类的源代码,违反了开闭原则;
  • 客户端只能通过new关键字来直接创建Chart对象,Chart类与客户端类耦合度较高,对象的创建和使用无法分离;
  • 客户端在创建Chart对象之前可能还需要进行大量初始化设置,例如设置柱状图的颜色和高度等,如果在Chart类的构造函数中没有提供一个默认设置,那就只能由客户端来完成初始设置,这些代码在每次创建Chart对象时都会出现,导致代码的重复;

二、简单工厂模式概述

2.1 要点

  简单工厂模式并不属于GoF 23种经典设计模式,但通常将它作为学习其他工厂模式的基础。

简单工厂(Simple Factory)模式:定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法模式,它属于创建型模式。

  简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需的对象,而无须知道其创建细节

2.2 结构图

  简单工厂模式包含3个角色:

  • Factory - 工厂角色:该模式的核心,负责实现创建所有产品实例的内部逻辑,提供一个静态的工厂方法GetProduct(),返回抽象产品类型Product的实例。
  • Product - 抽象产品角色:所有产品类的父类,封装了各种产品对象的共有方法,它的引入将提高系统的灵活性,使得在工厂类中只需要定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
  • ConcreteProduct - 具体产品角色:简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。

  在简单工厂模式中,客户端通过工厂类来创建一个产品类的实例,而无须直接使用new关键字来创建对象。(可以看出,它是工厂模式家族中最简单的一员)

三、重构图表库的实现

3.1 新的结构图

  为了将Chart类的职责分离,同时将Chart对象的创建和使用分离,M公司开发人员决定使用简单工厂模式对图表库进行重构,重构后的结构图如下所示:

3.2 新的代码实现

  (1)抽象产品角色:IChartable接口

    public interface IChartable
{
void Display();
}

  (2)具体产品角色:各种图表类型

    public class HistogramChart : IChartable
{
public HistogramChart()
{
Console.WriteLine("创建柱状图...");
} public void Display()
{
Console.WriteLine("显示柱状图...");
}
} public class LineChart : IChartable
{
public LineChart()
{
Console.WriteLine("创建折线图...");
} public void Display()
{
Console.WriteLine("显示折线图...");
}
} public class PieChart : IChartable
{
public PieChart()
{
Console.WriteLine("创建饼状图...");
} public void Display()
{
Console.WriteLine("显示饼状图...");
}
}

  (3)工厂角色:ChartFactory

    public class ChartFactory
{
public static IChartable GetChart(string type)
{
IChartable chart = null; if (type.Equals("histogram", StringComparison.OrdinalIgnoreCase))
{
chart = new HistogramChart();
Console.WriteLine("初始化设置柱状图...");
}
else if (type.Equals("pie", StringComparison.OrdinalIgnoreCase))
{
chart = new PieChart();
Console.WriteLine("初始化设置饼状图...");
}
else if (type.Equals("line", StringComparison.OrdinalIgnoreCase))
{
chart = new PieChart();
Console.WriteLine("初始化设置折线图...");
} return chart;
}
}

  (4)客户端调用:

    public static void Main()
{
IChartable chart = ChartFactory.GetChart("histogram");
if (chart != null)
{
chart.Display();
} chart = ChartFactory.GetChart("pie");
if (chart != null)
{
chart.Display();
}
}

  运行结果如下:

  在客户端代码中,使用工厂类的静态方法来创建具体产品对象,如果需要更换产品,只需要修改静态工厂方法中的参数即可。例如:将柱状图改为饼状图,只需要将代码:

IChartable chart = ChartFactory.GetChart("histogram");

  改为:

IChartable chart = ChartFactory.GetChart("pie");

3.3 改进的方案

  M公司开发人员发现在创建具体Chart对象时,每次更换一个Chart对象都需要修改客户端中静态工厂方法的参数,客户端代码需要重新编译,这对于客户端而言,是违反了开闭原则的。于是,开发人员希望有一种方法能够在不修改客户端代码地前提下更换具体产品对象。

  因此,他们考虑使用配置文件(XML)来实现:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="charttype" value="histogram"/>
</appSettings>
</configuration>

  客户端因此改为:

    public static void Main()
{
string type = AppConfigHelper.GetChartType(); // 读取配置文件中的charttype
if (string.IsNullOrEmpty(type))
{
return;
} IChartable chart = ChartFactory.GetChart(type);
if (chart != null)
{
chart.Display();
}
}

  运行结果如下:

四、简单工厂模式总结

4.1 主要优点

  • 实现了对象创建和使用的分离:客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品。
  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的的参数即可。
  • 通过引入配置文件,可以在不修改任何客户端代码地情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

4.2 主要缺点

  • 由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受影响。
  • 使用简单工厂模式势必会增加系统中类的个数(引入新的工厂类),增加了系统的复杂度和理解难度。
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能会造成工厂逻辑过于复杂,不利于系统的扩展和维护。
  • 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

4.3 适用场景

  • 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  • 客户端只需要知道传入工厂类的参数,对于如何创建对象并不关心。

来源:http://www.cnblogs.com/edisonchou/p/6683262.html

设计模式--简单工厂(Simple Factory)的更多相关文章

  1. 设计模式:简单工厂(Simple Factory)

    定义:根据提供的数据或参数返回几种可能类中的一种. 示例:实现计算器功能,要求输入两个数和运算符号,得到结果. 结构图: HTML: <html xmlns="http://www.w ...

  2. 简单工厂(Simple Factory),最合适的设计模式首秀.

    简单工厂又称为静态工厂方法(static factory method)模式,简单工厂是由一个工厂来决定创建出哪一种个体的实现,在很多的讨论中,简单工厂做为工厂方法模式(Factory Method) ...

  3. 使用C# (.NET Core) 实现简单工厂(Simple Factory) 和工厂方法设计模式 (Factory Method Pattern)

    本文源自深入浅出设计模式. 只不过我是使用C#/.NET Core实现的例子. 前言 当你看见new这个关键字的时候, 就应该想到它是具体的实现. 这就是一个具体的类, 为了更灵活, 我们应该使用的是 ...

  4. 设计模式~简单工厂模式(Factory)

    简单工厂模式Simple Factory根据提供给它的数据,返回一个类的实例.通常它返回的类都有一个公共的父类(或者接口对象). 简单工厂的作用是实例化对象,而不需要客户了解这个对象属于哪个具体的子类 ...

  5. Golang设计模式—简单工厂模式(Simple Factory Pattern)

    Golang设计模式--简单工厂模式 背景 假设我们在做一款小型翻译软件,软件可以将德语.英语.日语都翻译成目标中文,并显示在前端. 思路 我们会有三个具体的语言翻译结构体,或许以后还有更多,但现在分 ...

  6. java设计模式--简单工厂

    java设计模式--简单工厂 简单工厂不是一个标准的设计模式,但是很常用需要掌握. 在java应用开发中,要"面向接口编程". 1.java中接口的概念: 在java中接口是一种特 ...

  7. Yii2设计模式——简单工厂模式

    除了使用 new 操作符之外,还有更多的制造对象的方法.你将了解到实例化这个活动不应该总是公开进行,也会认识到初始化经常造成"耦合"问题. 应用举例 yii\db\mysql\Sc ...

  8. Yii2 设计模式——简单工厂模式

    除了使用 new 操作符之外,还有更多的制造对象的方法.你将了解到实例化这个活动不应该总是公开进行,也会认识到初始化经常造成“耦合”问题. 应用举例 yii\db\mysql\Schema 中: // ...

  9. 3. 星际争霸之php设计模式--简单工厂模式

    题记==============================================================================本php设计模式专辑来源于博客(jymo ...

  10. 深入浅出设计模式——简单工厂模式(Simple Factory)

    介绍简单工厂模式不能说是一个设计模式,说它是一种编程习惯可能更恰当些.因为它至少不是Gof23种设计模式之一.但它在实际的编程中经常被用到,而且思想也非常简单,可以说是工厂方法模式的一个引导,所以我想 ...

随机推荐

  1. vue下超级滚动条perfect-scrollbar(在特定框架里使用一款并非为该框架定制的库/插件)

    点我查看

  2. 八皇后问题 -- python面向对象解法

    # [8*8棋盘八皇后问题] class Queen: def __init__(self, row, col): self.row = row self.col = col self.pos = ( ...

  3. 条款2:尽量使用const ,enum,inline替换define

    宁可使用编译器而不用预处理器 假设我们使用预处理器: #define ABC 1.56 这标识符ABC也许编译器没看到,也许它在编译器处理源码前就被预处理器移走了,于是“标识符”ABC没有进入标识符列 ...

  4. 五、Angular定义字段、绑定字段、获取数据、对象获取数据、*ngFor循环获取数据,自定义方法、*ngIf条件判断、双向数据绑定

    1.定义属性 2.绑定属性.绑定html中 3.循环获取数据 编写的时候没有注意,第二个循环 i 需要改成 {{i}} ,这样才会显示 出效果 4.自定义方法 变量名截图省略 5.*ngIf条件判断 ...

  5. Sass函数:random()函数

    random() 函数是用来获取一个随机数 >> random() 0.03886 >> random() 0.66527 >> random() 0.8125 & ...

  6. [BZOJ3625][Codeforces Round #250]小朋友和二叉树 多项式开根+求逆

    https://www.lydsy.com/JudgeOnline/problem.php?id=3625 愉快地列式子.设\(F[i]\)表示权值为\(i\) 的子树的方案数,\(A[i]\)为\( ...

  7. 苹果正制造一款疯狂的“16K”VR耳机,效果到底有多牛?

    苹果一直以来都有传闻称正在研发一副增强现实眼镜,但今天的一份报告显示,他们希望在虚拟现实领域与Google,微软和Facebook竞争. 据CNET报道,苹果公司着眼于2020年发布的将AR和VR技术 ...

  8. 03.父工程pom、整合测试、SpringBootApplication注解

    父工程 idea点击spring-boot-starter-parent找到父工程spring-boot-dependencies模仿配置 父工程 <?xml version="1.0 ...

  9. Win7 ODBC驱动 Excel (转)

    “控制面板-管理工具-数据源(ODBC)”,打开“ODBC数据源管理器”窗口,然后“添加”,打开“创建新数据源”的窗口,最后选择Microsoft Access Driver(*.mdb)选项,往后等 ...

  10. mybatis源码分析之05一级缓存

    首先需要明白,mybatis的一级缓存就是指SqlSession缓存,Map缓存! 通过前面的源码分析知道mybatis框架默认使用的是DefaultSqlSession,它是由DefaultSqlS ...