设计模式的征途—2.简单工厂(Simple Factory)模式

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

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

1、从一个图表库谈起

  M公司想要基于C#语言开发一套图表库,该图表库能够为应用系统提供各类不一样外观的图标,例如柱状图、饼状图或折线图等。M公司图表库设计开发人员但愿为应用系统开发人员提供一套灵活易用的图表库,并且能够较为方便地对图表库进行扩展,以便于在未来增长一些新类型的图表。设计模式

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

    public class Chart
    {
        private string type; // 图表类型

        public Chart(object[][] data, string type)
        {
            this.type = type;

            if (this.type.Equals("histogram", StringComparison.OrdinalIgnoreCase))
            {
                // 初始化柱状图
            }
            else if (this.type.Equals("pie", StringComparison.OrdinalIgnoreCase))
            {
                // 初始化饼状图
            }
            else if (this.type.Equals("line", StringComparison.OrdinalIgnoreCase))
            {
                // 初始化折线图
            }
        }

        public void Display()
        {
            if (this.type.Equals("histogram", StringComparison.OrdinalIgnoreCase))
            {
                // 显示柱状图
            }
            else if (this.type.Equals("pie", StringComparison.OrdinalIgnoreCase))
            {
                // 显示饼状图
            }
            else if (this.type.Equals("line", StringComparison.OrdinalIgnoreCase))
            {
                // 显示折线图
            }
        }
    }

  客户端代码经过调用Chart类的构造函数来建立图表对象,根据参数type的不一样能够获得不一样类型的图标,而后再调用Display()方法来显示相应的图表。框架

  可是,不难看出,Chart类是一个巨大的类,存在不少问题:函数

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

2、简单工厂模式概述

2.1 要点

  简单工厂模式并不属于GoF 23种经典设计模式,但一般将它做为学习其余工厂模式的基础。学习

简单工厂(Simple Factory)模式:定义一个工厂类,它能够根据参数的不一样返回不一样类的实例,被建立的实例一般都具备共同的父类。由于在简单工厂模式中用于建立实例的方法是静态(static)方法,所以简单工厂模式又被称为静态工厂方法模式,它属于建立型模式。this

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

2.2 结构图

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

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

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

3、重构图表库的实现

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、简单工厂模式总结

4.1 主要优势

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

4.2 主要缺点

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

4.3 适用场景

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

参考资料

      DesignPattern

  刘伟,《设计模式的艺术—软件开发人员内功修炼之道》

 

相关文章
相关标签/搜索