****## 前言
在讲述之工厂方法模式前,我们来先了解简单工厂模式,简单工厂模式是最简单的设计模式之一,它虽然不属于GoF的23种设计模式,但是应用也较为频繁,同时它也是学习其他创建型模式的基础。下面我们来先了解下简单工厂模式,然后针对它的缺点来引出工厂方法模式。
简单工厂方法定义
简单工厂模式简单来说就是创建一个工厂类,通过输入的参数创建对象赋值给基类,完成对想要的派生类的调用,从而达成目标,具体的操作均在子类中完成,工厂类只负责运算逻辑和给基类赋值。在简单工厂模式中,只需要记住一个简单的参数即可获得所需的对象实例,它提供专门的核心工厂类来负责对象的创建,实现对象的创建和使用分离。该模式有三部分:
- 工厂方法类:实现创建所有实例的选择类型,被外界调用的接口。
- 抽象父类:所要创建的类的基类,描述类所有实例所共有的公共接口(方法),可以是抽象类也可是接口类型(interface),本例是抽象类。
- 具体子类:所有要创建的具体实例对象。
简单工厂代码实现
抽象产品类和工厂类合并,将静态工厂方法移到抽象产品类中,根据不同的参数创建不同类型的产品子类对象。只需要添加配置文件并更改相关参数读取参数即可,不要重新编译程序。
-
引入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使得一个类的实例化延迟到子类。
可以看出,在工厂方法模式的结构图有以下角色:
(1)抽象工厂(Creator): 充当抽象工厂角色,定义工厂类所具有的基本的操作,任何具体工厂都必须继承该抽象类。
(2)具体工厂(CreatorA):充当具体工厂角色,该类必须继承抽象工厂角色,实现抽象工厂定义的方法,用来创建具体车。
(3)抽象车(Car):充当抽象车角色,定义车类型所有具有的基本操作,具体车必须继承该抽象类。
(4)具体车(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(); }
工厂方法模式优缺点
优点:
- 在工厂方法中,用户只需要知道所要产品的具体工厂,无须关系具体的创建过程,甚至不需要具体产品类的类名。
- 在系统增加新的产品时,我们只需要添加一个具体产品类和对应的实现工厂,无需对原工厂进行任何修改,很好地符合了“开闭原则”。
缺点:
- 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,是的系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。