设计模式——工厂方法模式

shanzm-2020年4月3日 22:26:27

1. 简介

工厂方法模式(Factory Method Pattern)也称为工厂模式,又称为虚拟构造器模式或多态模式。html

在工厂方法模式中,工厂父类负责定义建立产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样作的目的是将产品类的实例化操做延迟到工厂子类中完成,即经过工厂子类来肯定究竟应该实例化哪个具体产品类。git

工厂方法模式主要类:github

  • Product抽象产品类(或是接口),派生出全部的具体产品类ConcreteProductAConcreteProductA ……数据库

  • ConcreteProduct 具体产品类,继承于Product抽象类设计模式

  • Factory 抽象工厂接口,全部的具体工厂类都是实现该接口框架

  • ConcreteFactory 具体工厂,实现了Factory接口,建立具体的产品对象ide

shanzm_FactoryMethodPattern_UML

注:在GoF的《设计模式:可复用面向对象软件的基础》,对工厂方法模式的描述中使用的是 Creator接口,其含有 FactoryMethod()方法


2. 示例1-计算器重构

2.1 背景说明

设计模式——简单工厂模式一文中,使用简单工厂模式建立了一个简单的四则计算器,工具

咱们须要一个抽象的Operation父类,派生出四个加减乘除子类设计

在工厂中根据传入的符号参数,生成不一样的运行类。日志

可是问题也就来了,如果添加一个新的运行类,咱们依旧能够继承于Operation抽象父类,override运算方法,而后在工厂中添加一个新的分支,建立该运算类。

那么问题就来了!按照设计原则——开闭原则,咱们应该开放扩展,关闭修改。在这里,咱们扩展了运算方法,可是同时也对Factory类进行了修改,这明显不符合开闭原则啊!

其实这就是简单工厂模式的缺点。

为了解决这个缺点,咱们引入工厂方法模式。(事实上,简单工厂模式是工厂方法模式的简化版,而不是由于简单工厂模式有缺点才演变为工厂方法模式的)

咱们对在简单工厂模式中实现的计算器进行进一步的重构

2.2 代码重构

提取出工厂接口:IFactory,分别建立每一个运行类的工厂类AddFactory,SubFactory,MulFactory,DivFactory

//工厂接口:抽象工厂
public interface IFactory
{
    Operation CreateOperation();
}

//加法运行工厂:具体工厂
public class AddFactory : IFactory
{
    public Operation CreateOperation()
    {
        return new OperationAdd();
    }
}

//减法运行工厂:具体工厂
public class SubFactory : IFactory
{
    public Operation CreateOperation()
    {
        return new OperationSub();
    }
}

//乘法运行工厂:具体工厂
public class MulFactory : IFactory
{
    public Operation CreateOperation()
    {
        return new OperationMul();
    }
}

//除法运行工厂:具体工厂
public class DivFactory : IFactory
{
    public Operation CreateOperation()
    {
        return new OperationDiv();
    }
}

这时咱们在客户端,能够这样使用:

static void Main(string[] args)
{
    //建立一个具体的工厂对象:加法工厂对象
    IFactory addFactory = new AddFactory();
    //使用加法工厂对象建立加法运算类
    Operation addOper = addFactory.CreateOperation();
    addOper.NumA = 2;
    addOper.NumB = 3;
    Console.WriteLine(addOper.GetResult());//print:5
    Console.ReadKey();
}

其实到这里是能够发现,通过重构后的代码,每一个具体运算类都有一个相应的工厂类

如果须要添加一个新的运行符,则咱们只须要建立一个新的具体工厂类XXXFactory,实现抽象工厂接口IFactory,同时再建立新的运算符实现类XXX,继承于运算抽象父类Operation。这样就能够在不修改程序中的现有的类的情形下,实现对程序的扩展!知足了开闭原则,避免了简单工厂模式的缺点!

工厂方法模式实现时,客户端须要决定实例化哪个工厂来实现运算类,选择判断的问题仍是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行。你想要加功能,原本是改工厂类的,而如今是修改客户端

2.3 程序类图

shanzm_计算器5.0

注1:类图是vs自动生成的,可是VS中没法生成`依赖关系`的图示,因此我本身用画图软件给补上来,便于理解程序中各个类的关系。
注2:实现接口在vs中自动生成的类中是使用棒棒糖表示法


3. 示例2-模拟多功能日记记录器

3.1 背景说明

示例来源于《设计模式实训-第二版》

某系统日志记录器要求支持多种日志记录方式,如文件日志记录(FileLog)、数据库日志记录(DatabaseLog)等,且用户能够根据要求动态选择日志记录方式,现使用工厂方法模式设计该系统。

这里我为何要用这个示例? 由于在实际开发中,一些框架和程序包都是按照工厂方法模式开发的,包括日志框架。

其实你想想,使用的一些框架和程序包的调用,是否是都先是建立一个ConcreteFactory对象(或者Creator对象),以后使用该具体工厂对象建立ConcreteProduct对象

好比:Quartz .NET任务调度框架

3.2 代码实现

①抽象产品和具体产品的实现代码

//抽象产品:日志记录器总接口(使用抽象类也能够)
public interface ILog
{
    void WriteLog();
}
//具体产品:文件日志记录器
public class FileLog : ILog
{
    public void WriteLog()
    {
        Console.WriteLine("记录日志于日志文件中");
    }
}
//具体产品:数据库日志记录器
public class DatabaseLog : ILog
{
    public void WriteLog()
    {
        Console.WriteLine("记录日志于日志数据库中");
    }
}

②抽象工厂和具体工厂的实现代码

//抽象工厂:日志记录器工厂
public interface ILogFactory
{
    ILog CreateLog();
}
//具体工厂:文件日记记录器工厂
public class FileLogFactory : ILogFactory
{
    public ILog CreateLog()
    {
        return new FileLog();
    }
}
//具体工厂:数据库日记记录器工厂
public class DatabaseLogFactory : ILogFactory
{
    public ILog CreateLog()
    {
        return new DatabaseLog();
    }
}

③客户端代码

class Program
{
    static void Main(string[] args)
    {
        //建立一个具体的工厂对象:FileLogFactory
        ILogFactory logFac = new FileLogFactory();
        //由工厂对象,建立产品对象:FileLog
        //FileLog log = logFac.CreateLog() as FileLog;
        ILog log = logFac.CreateLog();
        log.WriteLog();//print:记日志于日志文件中
        Console.ReadKey();
    }
}

3.3 程序类图



4. 总结分析

4.1 优势

  • 当调用者须要一个具体产品对象,只要使用该具体产品的具体工厂建立该对象便可。调用者不须要知道具体产品对象是怎么建立的

  • 便于扩展:使用工厂方法模式的另外一个优势是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其余的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就能够了。这样,系统的可扩展性也就变得很是好,彻底符合“开闭原则”。

  • 工厂方法模式是平行的类层次结构

    • 什么是平行的类层次结构?简单的说,假若有两个类的层次,其中一个层次中的类在另一个层次中都有相对应的类,则称这两个类层次是平行的类层次结构。工厂方法模式就是平行的类层次结构。这里能够看UML图,很是明显!工厂类层次和产品类层次就是平行的。

    • 这种平行的类层次结构用来干什么呢?主要用来把一个类层次中的某些行为分离出来,让类层次中的类把本来属于本身的职责,委托给分离出来的类去实现,从而使得类层次自己变得更简单,更容易扩展和复用。

4.2 缺点

  • 扩展系统的时候,一旦添加一个具体产品类,则必须同时添加一个相应的具体工厂类。因此系统中类的添加是成对的添加,必定程度上形成系统繁杂。

4.3 适应场合

  • 工厂方法模式是new一个对象的替代品。因此其实在须要大量实例化对象的地方都是可使用的。

  • 实际中开发中,工厂方法主要用于工具包和框架中

4.4 其余说明

  • 为何工厂方法模式也称为多态工厂模式?工厂接口的有不一样的实现(也就是多态),换一句说也就是具体工厂类都有同一个工厂接口。

  • 工厂方法模式的简化:如果产品对象较少,可使用一个具体工厂类(包含一个静态的工厂方法)根据参数去建立全部的具体产品,这就是所谓的简单工厂模式

    • 注意简单工厂模式就是经过参数化工厂方法实现的。参数化工厂方法具体指:经过给工厂方法传递参数,让工厂方法根据参数建立不一样的产品对象。

    • 详细可参考《研磨设计模式》



5. 参考及源码下载

相关文章
相关标签/搜索