工厂方法模式

144 阅读6分钟

一、工厂方法模式简介

1、定义

工厂方法模式又称工厂模式,也叫虚拟构造器模式或多态工厂模式,它属于类创建型模式

在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生产具体的产品对象,这样做的目的是将产品类的实例化操作延迟工厂子类中完成,


2、使用动机

现有对该系统进行修改,不再涉及一个按钮工厂来统一负责所有产品的创建,而是将具体按钮的创建过程交给专门的工厂子类去完成。

我们首先定义一个抽象的按钮工厂类,再定义具体的工厂类来完成圆形按钮、矩形按钮、菱形按钮等,它们实现在抽象按钮工厂类中定义的方法。这种抽象化的结果使这个结构可以在不修改具体工厂类的情况下引进新的产品,如果出现新的按钮类型,只需要为这种新类型的按钮创建一个具体的工厂类就可以获得该新按钮的实例,这一特点使得工厂方法模式具有超越简单工厂模式的优越性,更加符合“开闭原则”。


二、工厂方法模式结构

1、模式结构

所有图片和程序来源


工厂方法模式包含如下角色:

  • Product:抽象方法

工厂方法模式所创建的对象的超类,也就是所有产品类共同父类或者共同拥有的接口。在实际的系统中,该角色也常常使用抽象类实现。

  • ConcreteProduct:具体产品

该角色实现抽象产品(Product)所声明的接口,工厂方法模式所创建的每一个对象都是某个具体产品的实例

  • Factory:抽象工厂

担任这个角色的是工厂方法模式的核心,任何在模式中创建对象的工厂类必须实现这个接口。在实际的系统中,这个角色也常常使用抽象类实现。

  • ConcreteFactory:具体工厂

担任这个角色的是实现了这个抽象工厂接口的具体Java类,具体工厂角色包含与业务密切相关的逻辑,并且受到使用者的调用与创建具体产品对象。


2、时序图


  • 先调用具体工厂对象中的方法createProduct()
  • 根据传入产品类型参数(也可以无参),获得具体的产品对象
  • 返回产品对象并使用


三、工厂方法模式的使用实例

1、定义抽象产品的接口

public interface ILight
{
    void TurnOn();
    void TurnOff();
}

2、实现抽象接口的具体产品类

具体产品类:BulbLight

public class BulbLight implements ILight
{
    public void TurnOn()
    {
        Console.WriteLine("BulbLight turns on.");
    }
    public void TurnOff()
    {
        Console.WriteLine("BulbLight turns off.");
    }
}

具体产品类:TubeLight

public class TubeLight implements ILight
{
    public void TurnOn()
    {
        Console.WriteLine("TubeLight turns on.");
    }

    public void TurnOff()
    {
        Console.WriteLine("TubeLight turns off.");
    }

}

3、抽象的工厂类

public interface ICreator
{
    ILight CreateLight();
}

4、实现抽象工厂类的具体工厂类

具体工厂类:BulbCreator

public class BulbCreator implements ICreator
{
    public ILight CreateLight()
    {
        return new BulbLight();
    }

}

具体工厂类:TubeCreator

public class TubeCreator implements ICreator
{
    public ILight CreateLight()
    {
        return new TubeLight();
    }
}


5、测试

public static void Main(string[] args)
{
    //先给我来个灯泡
    ICreator creator = new BulbCreator();
    ILight light = creator.CreateLight();
    light.TurnOn();
    light.TurnOff();

    //再来个灯管看看
    creator = new TubeCreator();
    light = creator.CreateLight();
    light.TurnOn();
    light.TurnOff();

}


总结:

创建一个产品接口,一个工厂接口,(产品抽象类和工厂抽象类也可以)

定义多个具体产品类和产品对应的具体工厂类

而后通过具体的工厂类调动具体的产品类


四、工厂方法模式的优缺点


1、优点

  • 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏哪些具体产品类被实例化的细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名
  • 基于工厂角色和产品角色多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又称为多态工厂模式,是因为所有的具体工厂类都具有同一个抽象父类
  • 使用工厂方法模式的另外一个优点是在系统中加入新产品时,无须修改抽象工厂抽象产品提供的接口,无须修改客户端,也无须修改其他具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合开闭原则”,这点比简单工厂模式更优秀。

2、缺点

  • 在添加新产品时,需要编写新的具体产品类,而且还要提供与之相对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销
  • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码总均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能用到DOM、反射等技术,增加了系统的实现难度。


五、使用场景

在下面情况下可以使用工厂方法模式:

  • 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
  • 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类确定具体要创建的对象,利用面对对象的多态性和里氏代换原则,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。
  • 创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心哪一个工厂类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。


六、工厂方法模式在Java中应用

JDBC中的工厂方法:

Connection conn=DriverManager.getConnection("jdbc:microsoft:sqlserver://localhost:1433; 
                  DatabaseName=DB;user=sa;password=");
Statement statement=conn.createStatement();
ResultSet rs=statement.executeQuery("select * from UserInfo");