设计模式之 - 工厂方法模式

291 阅读4分钟
  • 携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情

前言

工厂方法模式(Factort Method)是一种常用的类创建型设计模式。

简单工厂模式

聊到工厂方法必须要说到的就是简单工厂模式,工厂类是整个模式的关键。在使用的时候仅需要传入参数,让工厂类去创建实例,无需去管这些对象究竟如何创建及如何组织的。

  • 举一个例子,A运输公司在最初运营的时候由于资金问题采用了三轮车送货,此时我们需要创建一个抽象类Transport定义一个Delivery虚方法,再创建一个Tricycle类继承Transport类并且实现Delivery方法,然后实例化Tricycle类调用Delivery方法,代码如下!
// 定义抽象类
public abstract class Transport 
{
    public virtual void Cargo() { }
}

public class Tricycle : Transport
{
    public override void Cargo()
    {
        Console.WriteLine("使用三轮车送货中······");
    }
}

static void Main(string[] args)
{
    //调用
    Tricycle tricycle = new Tricycle();
    tricycle.Cargo();
}
  • A运输公司由于发展迅速,需要提供运输效率,特意采用国产电动货车支持新能源,代码在上面基础做出如下改变!
public class Minivan : Transport
{
    public override void Cargo()
    {
        Console.WriteLine("使用小货车送货中······");
    }
}

static void Main(string[] args)
{
    //调用
    Tricycle tricycle = new Tricycle();
    tricycle.Cargo();
    
    Minivan minivan = new Minivan();
    minivan.Cargo();
}

传统写法会造成什么问题呢?无疑是创建和使用太过于耦合了,并且没有地方来统一管理会导致如果使用地方较多,会产生大量的重复代码。接下来我们使用简单工厂来实现看看。

  • 创建工厂CargoFactort类
public class CargoFactort
{
    // 参数为CarType 根据参数自动实例化类
    public Transport CreateCargo(CarType type)
    {
        Transport transport = null;

        switch (type) 
        {
            case CarType.Tricycle:
                transport = new Tricycle();
                break;
            case CarType.Minivan:
                transport = new Minivan();
                break;
            default:
                break;
        }

        return transport;
    }
}
  • 调用:无需实例化,直接调用工厂即可,也不用管对象是如何创建的。
static void Main(string[] args)
{
    var tricycle = CargoFactort.CreateCargo(CarType.Tricycle);
    tricycle.Cargo();
}
  • 还是上面场景,A运输公司由于客户单量过多小货车无法满足需求,又订购了一批大卡车,此时我们项目做出如下修改:新增卡车类Truck实现Cargo方法,在工厂类Switch新增节点。
switch (type) 
{
    case CarType.Tricycle:
        transport = new Tricycle();
        break;
    case CarType.Truck: // 新增卡车类节点
        transport = new Truck();
        break;
    case CarType.Minivan:
        transport = new Minivan();
        break;
    default:
        break;
}

疑问? 如果直接修改工厂类会产生什么问题呢,违背了软件设计原则(开闭原则)。

开闭原则:一个软件实体,如类、模块和函数应该对扩展开放,对修改关闭。换句话说就是当你的类独立了就不应该修改它,只能提供方法去扩展它。

工厂方法模式

针对上述问题衍生出了工厂方法模式,完全实现了开-闭原则,适用于更为复杂的场景。工厂方法模式的核心结构有四个角色,分别如下。

  • 抽象工厂:是工厂方法模式的核心,类声明返回产品对象的工厂方法。 该方法的返回对象类型必须与产品接口相匹配。
  • 具体工厂:抽象工厂的实现, 使其返回不同类型的产品。
  • 抽象产品:将会对接口进行声明。 对于所有由创建者及其子类构建的对象, 这些接口都是通用的。
  • 具体产品:抽象产品的实现

image.png

类图1-1 如上(百度百科)

  • 根据如上概念,我们讲上面业务场景进行代码优化如下
static void Main(string[] args)
{
    TransportCreator transport = new TruckFactory();
    Transport truck = transport.CreateTransport();
    truck.Cargo();
}

//产品
public abstract class Transport
{
   public abstract void Cargo();
}

// 创建者
public abstract class TransportCreator 
{
    public abstract Transport CreateTransport();
}

// 具体产品
public class Truck : Transport
{
    public override void Cargo()
    {
        Console.WriteLine("使用卡车送货中······");
    }
}

//具体创建者
public class TruckFactory : TransportCreator
{
    public override Transport CreateTransport()
    {
        return new Truck();
    }
}

如果需要在实现一个三轮车,只需要创建一个具体创建者TricycleFactory,新增一个具体产品Tricycle实现Cargo方法即可。

总结

工厂方法将创建产品的代码与实际使用产品的代码分离, 从而能在不影响其他代码的情况下扩展产品创建部分代码,解决了简单工厂模式违背的开闭原则。但是不难看出,应用工厂方法模式需要引入许多新的类, 代码结构会变得复杂起来。