设计模式的艺术之道--简单工厂模式

设计模式的艺术之道–简单工厂模式

声明:本系列为刘伟老师博客内容总结(http://blog.youkuaiyun.com/lovelion),博客中有完整的设计模式的相关博文,以及作者的出版书籍推荐

本系列内容思路分析借鉴了刘伟老师的博文内容,同时改用C#代码进行代码的演示和分析(Java资料过多 C#表示默哀).

本系列全部源码均在文末地址给出。

本系列开始讲解创建型模式,顾名思义,这类模式主要是为了解决类的创建问题。

  • 创建型模式(Creational Pattern)关注对象的创建过程。分析你怎么来的
  • 创建型模式对类的实例化过程进行了抽象,对用户隐藏了类的实例的创建细节。客户不知道你怎么来的
  • 创建型模式描述如何将对象的创建和使用分离,让用户在使用对象时无须关心对象的创建细节。你用就行,别管我怎么来的。
  • 创建型模式关注点 创建什么(What) 由谁创建(Who) 何时创建(When)
    6种常见的创建型模式

这里写图片描述

简单工厂模式

1.1定义

  • 简单工厂模式 (Simple Factory Pattern):定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式。
  • 哆啦A梦的百宝箱(工厂类),大熊(客户端)要什么我给你造什么。
    开个小饭馆,自己是是老板也是厨师,客户让做啥,我给你做出啥来。

1.2情景实例

问题描述
- 图表库的设计
菜鸟软件公司欲开发一套图表库,该图表库可以为应用系统提供各种不同外观的图表,例如柱状图、饼状图、折线图等。图表库设计人员希望为应用系统开发人员提供一套灵活易用的图表库,而且可以较为方便地对图表库进行扩展,以便能够在将来增加一些新类型的图表。

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

class Chart {  
    private String type; //图表类型  

    public Chart(Object[][] data, String type) {  
        this.type = type;  
        if (type.equalsIgnoreCase("histogram")) {  
            //初始化柱状图  
        }  
        else if (type.equalsIgnoreCase("pie")) {  
            //初始化饼状图  
        }  
        else if (type.equalsIgnoreCase("line")) {  
            //初始化折线图  
        }  
    }  

    public void display() {  
        if (this.type.equalsIgnoreCase("histogram")) {  
            //显示柱状图  
        }  
        else if (this.type.equalsIgnoreCase("pie")) {  
            //显示饼状图  
        }  
        else if (this.type.equalsIgnoreCase("line")) {  
            //显示折线图  
        }     
    }  
}  

现有缺点(未来变化)

  • (1) 在Chart类中包含很多“if…else…”代码块,难以阅读理解。
  • (2) Chart类的职责过重,负责了所有的图标初始化和显示,违反单一职责原则
  • (3)当需要增加新类型的图表时,必须修改Chart类的源代码,违反开闭原则
  • (4) 客户端只能通过new关键字来直接创建Chart对象,耦合度高。

如何改进
引入简单工厂模式

  • 对产品类进行重构,根据实际情况设计一个产品层次结构。抽象归类
  • 将产品类公共的代码移至抽象产品类,不同部分设计为虚方法或者抽象方法
    UML类图
    这里写图片描述
    实例关键代码
namespace SimpleFactory
{
    interface Chart
    {
        //抽象的产品类
        void Display();
    }

    class LineChart : Chart
    {
        //具体的产品类
        public LineChart() 
        {
            Console.WriteLine("创建折线图!");
        }

        public void Display() 
        {
            Console.WriteLine("显示折线图!");
        }
    }

    class ChartFactory
    {
        //生产对象的方法
        //静态工厂方法 
        public static Chart GetChart(string type) 
        {
            Chart chart = null;
            if (type.Equals("histogram")) 
            {
                chart = new HistogramChart();
                Console.WriteLine("初始化设置柱状图!");
            }
            else if (type.Equals("pie")) 
            {
                chart = new PieChart();
                Console.WriteLine("初始化设置饼状图!");
            }
            else if (type.Equals("line")) 
            {
                chart = new LineChart();
                Console.WriteLine("初始化设置折线图!");         
            }
            return chart;
        }
      }

    class Program
    {
        //客户端调用
        static void Main(string[] args)
        {

            Chart chart;
            //读取配置文件  通过读取配置文件的方式修改传入的参数 避免了源代码修改
            //配置文件使用先在工程里添加system.configuration.dll程序集的引用
            string chartStr = ConfigurationManager.AppSettings["chartType"];
            chart = ChartFactory.GetChart(chartStr); //通过静态工厂方法创建产品
            chart.Display();

            Console.Read();
        }
    }
}

1.3模式分析

动机和意图

  • 只需要知道产品的名字则可得到相应的产品
  • 不需要去关心产品怎么来,我需要你就给我

一般结构

  • 简单工厂模式包含如下角色:
  • Factory:工厂角色 负责创建产品
  • Product:抽象产品角色 产品的抽象归类提升
  • ConcreteProduct:具体产品角色 工厂输出的产品

改进的优点

  • 降低了客户端与具体产品的耦合,只需要知道他是什么
  • 客户端只需要与工厂打交道,告诉需要什么

现存的缺点

  • 工厂类内部存在大量判断,产品过多将会过于复杂
  • 一旦增加新产品,工厂类就得修改,并且增加新的产品类
  • 工厂类集中了所有产品的创建逻辑,职责过重

适用场景
(1) 工厂类负责创建的对象比较少,里边的种类划分较少或者不易发生变化。
(2) 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
举例:小王去 沙县小吃吃饭(老板一个人干活) 桌面显示不同的图形显示(三角形 矩形 圆形 常规图形)
实例源代码
GitHub地址
百度云地址:链接: https://pan.baidu.com/s/1mhYHXcW 密码: qz3u

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值