简单工厂模式是最简单的设计模式之一,它虽然属于GoF的23种设计模式,但是应用也较为频繁,同时它也是学习其他创建型模式的基础。在简单工厂模式中,只需要记住一个简单的参数即可获得所需的对象实例,它提供专门的核心工厂类来负责对象的创建,实现对象的创建和使用分离。
创建型模式对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离,对用户隐藏了类的实例创建细节。
每一个创建型模式都通过采用不同的解决方案来回答3个问题:创建什么(What), 由谁创建(Who)和何时创建(When)。
简单工厂模式概述
首先将需要创建的各种不同产品对象的相关代码封装到不同的类中,这些类称为具体产品类,而将它们公共的代码进行抽象和提取后封装在一个抽象产品类中,每一个具体产品类都是抽象产品类的子类;然后提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方法,该方法可以根据所传入的参数的不同创建不同的具体产品对象;客户端只需要调用工厂类的工厂方法并传入相应的参数即可得到一个产品对象。
定义
简单工厂模式(Simple Factory Patter): 定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
由于在简单工厂模式中用于创建实例的方法通常是静态方法,所以简单工厂模式又被称为静态工厂方法模式,它是一类创建型模式。
简单工厂模式的结构与实现
简单工厂模式结构图简单工厂模式包含以下3个角色:
- Factory(工厂角色): 工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法FactoryMethod(),它返回的类型为抽象产品类型Product。
- Product(抽象产品角色): 它是工厂类所创建的所有对象的父类,封装了各种产品对象的公共方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用得工厂方法,因为所有创建的具体产品对象都是其子类的对象。
- ConcreteProduce(具体产品角色): 它使简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中的声明的抽象方法。
简单工厂模式的实现
抽象工厂类:
public abstract class Product
{
// 所有产品类的公共业务方法
public void MethodSame()
{
Console.WriteLine("处理公共业务方法");
}
// 声明抽象业务方法
public abstract void MethidDiff();
}
具体工厂类A:
{
// 实现业务方法
public override void MethidDiff()
{
Console.WriteLine("具体产品A处理业务方法");
}
}
具体工厂类B:
public class ConcreteProduceB: Product
{
// 实现业务方法
public override void MethidDiff()
{
Console.WriteLine("具体产品B处理业务方法");
}
}
简单工厂模式的核心,工厂类:
public class Factory
{
// 静态工厂方法
public static Product GetProduct(string arg) =>
arg switch
{
"A" => new ConcreteProduceA(),
"B" => new ConcreteProduceB(),
_ => throw new ArgumentException(message: "invalid arg value"),
};
}
客户端调用:
// 简单工厂模式
var productA = Factory.GetProduct("A");
productA.MethodSame();
productA.MethidDiff();
var productB = Factory.GetProduct("B");
productB.MethodSame();
productB.MethidDiff();
测试结果
由示例可以看出,必须通过修改客户端代码中静态方法的参数来更换具体产品对象,客户端代码需要重新编译,这对于客户端而言,违背了开闭原则。
下面介绍一种常用的解决方案,利用App.config配置文件的方式,提高系统的灵活性。只需要添加配置文件和修改客户端使用方式即可。
代码示例:
App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<appSettings>
<add key="Product" value="A" />
</appSettings>
</configuration>
调用方式:
// 简单工厂模式 + 配置文件
var type = System.Configuration.ConfigurationManager.AppSettings["product"];
var productA = Factory.GetProduct(type);
productA.MethodSame();
productA.MethidDiff();
测试结果
有时为了简化简单工厂模式,可以将抽象产品类和工厂类合并,将静态工厂方法移到抽象产品类中,根据不同的参数创建不同类型的产品子类对象,这种方法在很多类库和框架中也广泛存在。
代码示例:
public abstract class Product
{
// 静态工厂方法
public static Product GetProduct(string arg) =>
arg switch
{
"A" => new ConcreteProduceA(),
"B" => new ConcreteProduceB(),
_ => throw new ArgumentException(message: "invalid arg value"),
};
// 所有产品类的公共业务方法
public void MethodSame()
{
Console.WriteLine("处理公共业务方法");
}
// 声明抽象业务方法
public abstract void MethidDiff();
}
调用方式:
// 简单工厂模式 + 配置文件 + 合共抽象产品类和工厂类
var type = System.Configuration.ConfigurationManager.AppSettings["product"];
var productA = Product.GetProduct(type);
productA.MethodSame();
productA.MethidDiff();
测试结果
简单工厂模式的优缺点与适用环境
简单工厂的优点
- 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的职责,而仅仅“消费”产品,简单工厂模式实现了对象创建和使用的分离。
- 客户端无须知道所创建的具体产品类的类名,只需知道具体产品类所对应的参数即可。
- 通过引入配置文件,可以在不修改任何客户端代码的情况下,更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
简单工厂模式的缺点
- 由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响。
- 使用简单工厂模式势必会增加系统中类的个数,增加了系统的复杂度和理解难度。
- 系统扩展难度,一旦添加新产品不得不修改工厂逻辑,在产品类型加多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展与维护。
- 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
简单工厂模式的适用环境
- 工厂类负责创建的对象比较少
- 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
如果觉得文章写得还行,请点个赞。如果想与我进一步交流,可以关注我的公众号或者加我的微信。
个人微信公众号_DotNet微说.jpg
网友评论