天天看点

GOF设计模式-创建型模式-简单工厂模式工厂三兄弟之简单工厂模式

工厂三兄弟之简单工厂模式

模式定义:

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

多读几遍定义 然后我们来看下它的结构:

GOF设计模式-创建型模式-简单工厂模式工厂三兄弟之简单工厂模式

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

来来来  举个栗子:

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

然后程序员出了个设计方案,并将图表的实现代码封装在Chart类中:

/**  * description:  
* Created by yueli  
* on 2019/7/9  
*/ 
public 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")) {
            //显示折线图
        }
    } 
}      

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

不难看出,Chart类是一个“巨大的”类,在该类的设计中存在如下几个问题:

(1) 在Chart类中包含很多“if…else…”代码块,整个类的代码相当冗长,代码越长,阅读难度、 维护难度和测试难度也越大;而且大量条件语句的存在还将影响系统的性能,程序在执行过 程中需要做大量的条件判断。

(2) Chart类的职责过重,它负责初始化和显示所有的图表对象,将各种图表对象的初始化代码 和显示代码集中在一个类中实现,违反了“单一职责原则”,不利于类的重用和维护;而且将大 量的对象初始化代码都写在构造函数中将导致构造函数非常庞大,对象在创建时需要进行条 件判断,降低了对象创建的效率。

(3) 当需要增加新类型的图表时,必须修改Chart类的源代码,违反了“开闭原则”。

(4) 客户端只能通过new关键字来直接创建Chart对象,Chart类与客户端类耦合度较高,对象的 创建和使用无法分离。

(5) 客户端在创建Chart对象之前可能还需要进行大量初始化设置,例如设置柱状图的颜色、高 度等,如果在Chart类的构造函数中没有提供一个默认设置,那就只能由客户端来完成初始设 置,这些代码在每次创建Chart对象时都会出现,导致代码的重复。

面对这种如此巨大、职责如此重,且与客户端代码耦合度非常高的类,我们应该怎么办?

先上代码 看看我们用简单工厂模式改造后的效果:

/**
 * description:
 * Created by yueli
 * on 2019/7/9
 */
//抽象图表接口:抽象产品类
interface Chart  {
    public void display();
}

//柱状图类:具体产品类
class HistogramChart implements Chart  {
    public HistogramChart()   {
        System.out.println("创建柱状图!");
    }
    public void display()  {
        System.out.println("显示柱状图!");
    }
}
//饼状图类:具体产品类 
class PieChart   implements Chart  {                 
    public PieChart() {                             
        System.out.println("创建饼状图!");                 
    }     
    public void display()  {                             
        System.out.println("显示饼状图!");                 
    }     
}
//折线图类:具体产品类 
class LineChart  implements Chart  {                 
    public LineChart()    {                             
        System.out.println("创建折线图!");                 
    }     
public void display()  {                             
        System.out.println("显示折线图!");                 
    }     
}

//图表工厂类:工厂类 
class ChartFactory   {                 
    //静态工厂方法 
 public static Chart  getChart(String    type)  {                             
        Chart  chart  =  null;                             
        if (type.equalsIgnoreCase("histogram"))   {                                         
            chart  =  new HistogramChart();                                         
            System.out.println("初始化设置柱状图!");                              
        }else if (type.equalsIgnoreCase("pie")) {                                         
            chart  =  new PieChart();                                           
            System.out.println("初始化设置饼状图!");                              
        }else if (type.equalsIgnoreCase("line"))    {                                         
            chart  =  new LineChart();                                          
            System.out.println("初始化设置折线图!");   
        }                             
        return chart;                
    }     
}
//编写如下客户端测试代码:
class Client {                 
    public static void main(String    args[])    {                             
        Chart  chart;                            
        chart  =  ChartFactory.getChart("histogram");    //通过静态工厂方法创建产品 
 chart.display();                  
        }     
}      

现在的代码结构:

GOF设计模式-创建型模式-简单工厂模式工厂三兄弟之简单工厂模式

是不是对强迫症很治愈!!!当我们需要切换实例时唯一的改动只是客户端的入参:

chart = ChartFactory.getChart("pie");

但是还是有改动,不符合开闭原则了,我要换图表还是要改客户端的代码。这时候我们的解决办法是将静态工厂方法的参数存储在properties中然后在程序中引用它:

 String type = XMLUtil.getChartType(); //读取配置文件中的参数         

 chart = ChartFactory.getChart(type); //创建产品对象  

至此简单工厂模式的设计demo就讲完了。

下面我们分析下这种模式:

简单工厂模式的优点:

1.客户端免除了创建产品对象的职责,仅仅是“消费“产品,实现了对象和使用的分离;

2.客户端无需知道具体产品类的类名,只需知道对应产品的对应入参,减少记忆量;

3.通过引入配置文件可以不修改客户端的情况下更换产品,提高灵活性;

缺点:

1.工厂类集中了所有产品的创建逻辑,职责过重;

2.式势必会增加系统中类的个数,增加了系统的复杂 度和理解难度;

3. 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成 工厂逻辑过于复杂,不利于系统的扩展和维护。

4.由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

适用场景:

(1) 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太 过复杂。

(2) 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。

来来思考下为啥静态?

static方法可以通过类名访问,也可以通过类的实例访问。

static方法不能访问类中非static的数据。

比如

class A {      static void F(){} };

 在main函数中可以

A a;

a.F();

也可以 A.F();

普通方法又叫实例方法,只能通过类的实例访问。

他只能a.F();     

一个JAVA类被加载的顺序:

1.加载静态成员、代码块

2.加载非静态成员、代码块

3.调用构造方法。

其实不用静态方法也可以,只是用静态方法之后,就不用初始化工厂而直接得到产品。

继续阅读