在讲述之工厂方法模式前,我们来先了解简单工厂模式,简单工厂模式是最简单的设计模式之一,它虽然不属于GoF的23种设计模式,但是应用也较为频繁,同时它也是学习其他创建型模式的基础。下面我们来先了解下简单工厂模式,然后针对它的缺点来引出工厂方法模式。
简单工厂模式简单来说就是创建一个工厂类,通过输入的参数创建对象赋值给基类,完成对想要的派生类的调用,从而达成目标,具体的操作均在子类中完成,工厂类只负责运算逻辑和给基类赋值。在简单工厂模式中,只需要记住一个简单的参数即可获得所需的对象实例,它提供专门的核心工厂类来负责对象的创建,实现对象的创建和使用分离。该模式有三部分:
抽象产品类和工厂类合并,将静态工厂方法移到抽象产品类中,根据不同的参数创建不同类型的产品子类对象。只需要添加配置文件并更改相关参数读取参数即可,不要重新编译程序。
引入NuGet包:System.Configuration.ConfigurationManager
添加配置文件:App.config
文件,追加内容
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!--节点下添加配置,根据此配置,读取参数决定创建哪个Product-->
<add key="Product" value="B" />
</appSettings>
</configuration>
创建抽象父类和具体子类
抽象类:包含工厂方法
/// <summary>
/// 【01】抽象工厂类
/// </summary>
public abstract class Product
{
/// <summary>
/// 静态工厂方法
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
public static Product GetProduct(string arg)
{
Product product = null;
switch (arg)
{
case "A":
product = new ProduceA();
break;
case "B":
product = new ProduceB();
break;
//注意:有新产品需要修改工厂方法和创建新具体产品
default:
throw new ArgumentException(message: "参数不合法");
}
return product;
}
/// <summary>
/// 所有产品类的公共业务方法
/// </summary>
public void MethodSame()
{
Console.WriteLine("公共业务方法");
}
/// <summary>
/// 声明抽象业务方法
/// </summary>
public abstract void MethodDiff();
}
具体子类:
/// <summary>
///【02】具体工厂类A
/// </summary>
public class ProduceA : Product
{
/// <summary>
/// 实现业务方法
/// </summary>
public override void MethodDiff()
{
Console.WriteLine("产品A处理业务方法");
}
}
/// <summary>
///【03】具体工厂类B
/// </summary>
public class ProduceB : Product
{
/// <summary>
/// 实现业务方法
/// </summary>
public override void MethodDiff()
{
Console.WriteLine("产品B处理业务方法");
}
}
调用
/// <summary>
/// 调用测试方法
/// </summary>
public void RunTest()
{
//客户端调用
var type = ConfigurationManager.AppSettings["product"];//根据配置文件中参数,传入工厂方法,决定创建具体Product
Product oneProduct = Product.GetProduct(type);
oneProduct.MethodSame();
oneProduct.MethodDiff();
}
简单工厂模式中,我们也发现了它的缺点,就是随着需求的变化我们要不停地修改工厂里面的方法的代码,需求变化越多,里面的If–Else–也越多,这样就会造成简单工厂的实现逻辑过于复杂。设计模式是遵循一定原则而得来的,比如,我们要怎么增加代码,怎么修改代码,其中一个原则就是OCP原则,中文是【开放关闭原则】,对增加代码开放,对修改代码关闭,所以我们就不能总是这样修改简单工厂里面的方法。
工厂方法模式可以解决简单工厂模式中存在的这个问题,定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。
可以看出,在工厂方法模式的结构图有以下角色:
抽象工厂(Creator): 充当抽象工厂角色,定义工厂类所具有的基本的操作,任何具体工厂都必须继承该抽象类。
具体工厂(CreatorA):充当具体工厂角色,该类必须继承抽象工厂角色,实现抽象工厂定义的方法,用来创建具体车。
抽象车(Car):充当抽象车角色,定义车类型所有具有的基本操作,具体车必须继承该抽象类。
具体车(CarA):充当具体车角色,实现抽象车类对定义的抽象方法,由具体工厂类创建,它们之间有一一对应的关系。
简单工厂模式的问题是:如果有新的需求,就需要修改工厂类里面创建产品对象实例的那个方法的实现代码,在面向对象设计一个原则就是哪里有变化,我就封装哪里。
抽象汽车类
/// <summary>
/// 汽车抽象类
/// </summary>
public abstract class Car
{
/// <summary>
/// 开始行驶
/// </summary>
public abstract void Go();
}
具体汽车类
/// <summary>
/// ConcreteCar 具体车辆类
/// </summary>
public class ConcreteCar
{
/// <summary>
/// 红旗汽车
/// </summary>
public class HongQiCar : Car
{
public override void Go()
{
Console.WriteLine("红旗汽车开始行驶了!");
}
}
/// <summary>
/// 奥迪汽车
/// </summary>
public class AoDiCar : Car
{
public override void Go()
{
Console.WriteLine("奥迪汽车开始行驶了");
}
}
}
抽象工厂
/// <summary>
/// 抽象工厂类
/// </summary>
public abstract class Factory
{
/// <summary>
/// 工厂方法
/// </summary>
/// <returns></returns>
public abstract Car CreateCar();
}
具体工厂
/// <summary>
/// ConcreteFactory 具体工厂方法
/// </summary>
public class ConcreteFactory
{
/// <summary>
/// 红旗汽车工厂类
/// </summary>
public class HongQiCarFactory : Factory
{
/// <summary>
/// 负责生产红旗汽车
/// </summary>
/// <returns></returns>
public override Car CreateCar()
{
return new HongQiCar();
}
}
/// <summary>
/// 奥迪汽车工厂类
/// </summary>
public class AoDiCarFactory : Factory
{
/// <summary>
/// 负责创建奥迪汽车
/// </summary>
/// <returns></returns>
public override Car CreateCar()
{
return new AoDiCar();
}
}
}
调用
/// <summary>
/// 测试方法
/// </summary>
public void RunTest()
{
// 初始化创建汽车的两个工厂
Factory hongQiCarFactory = new HongQiCarFactory();
Factory aoDiCarFactory = new AoDiCarFactory();
// 生产一辆红旗汽车
Car hongQi = hongQiCarFactory.CreateCar();
hongQi.Go();
//生产一辆奥迪汽车
Car aoDi = aoDiCarFactory.CreateCar();
aoDi.Go();
}
优点:
缺点: