众所周知,C#是一种面向对象的语言,而其中封装,继承,多态是面向对象的三大重要特征,简单工厂的设计模式则可以完全体现这些特征。要彻底理解这个模式,必须要先将封装(访问修饰符的应用)、继承(基类和派生类的概念)、多态(重载,虚方法,重写,抽象方法的概念)全部搞懂,并能灵活运用。
简单工厂模式是最简单的设计模式之一,它虽然属于GoF的23种设计模式,但是应用也较为频繁,同时它也是学习其他创建型模式的基础。在简单工厂模式中,只需要记住一个简单的参数即可获得所需的对象实例,它提供专门的核心工厂类来负责对象的创建,实现对象的创建和使用分离。
创建型模式对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离,对用户隐藏了类的实例创建细节。
每一个创建型模式都通过采用不同的解决方案来回答3个问题:创建什么(What), 由谁创建(Who)和何时创建(When)。
简单工厂模式简单来说就是创建一个工厂类,通过输入的参数创建对象赋值给基类,完成对想要的派生类的调用,从而达成目标,具体的操作均在子类中完成,工厂类只负责运算逻辑和给基类赋值。该模式有三部分:
简单工厂模式(Simple Factory Patter): 定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
由于在简单工厂模式中用于创建实例的方法通常是静态方法,所以简单工厂模式又被称为静态工厂方法模式,它是一类创建型模式。
概述【进一步加深理解】:
- 首先将需要创建的各种不同产品对象的相关代码封装到不同的类中,这些类称为具体产品类。
- 而将它们公共的代码进行抽象和提取后封装在一个抽象产品类中,每一个具体产品类都是抽象产品类的子类;
- 然后提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方法,该方法可以根据所传入的参数的不同创建不同的具体产品对象;
- 客户端只需要调用工厂类的工厂方法并传入相应的参数即可得到一个产品对象。
简单工厂模式结构图如下:
简单工厂模式包含以下3个角色:
using System;
namespace ConsoleApp1
{
// 【01】抽象工厂类
public abstract class Product
{
// 所有产品类的公共业务方法
public void MethodSame()
{
Console.WriteLine("处理公共业务方法");
}
// 声明抽象业务方法
public abstract void MethodDiff();
}
// 【02】具体工厂类A
public class ConcreteProduceA : Product
{
// 实现业务方法
public override void MethodDiff()
{
Console.WriteLine("具体产品A处理业务方法");
}
}
//【03】具体工厂类B
public class ConcreteProduceB : Product
{
// 实现业务方法
public override void MethodDiff()
{
Console.WriteLine("具体产品B处理业务方法");
}
}
//【04】工厂类【简单工厂模式的核心】
public static class Factory
{
// 静态工厂方法
public static Product GetProduct(string arg)
{
Product product = null;
switch (arg)
{
case "A":
product = new ConcreteProduceA();
break;
case "B":
product = new ConcreteProduceB();
break;
default:
throw new ArgumentException(message: "Invalid arg value");//If the arg is not "A" or "B",throw an exception.
}
return product;
}
}
//【05】客户端调用
class Program
{
static void Main(string[] args)
{
//实例化产品A,并调用
try
{
Product productA = Factory.GetProduct("A");
//var productA = Factory.GetProduct("A");
productA.MethodSame();
productA.MethodDiff();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
//实例化产品B,并调用
try
{
Product productB = Factory.GetProduct("B");
//var productB = Factory.GetProduct("B");
productB.MethodSame();
productB.MethodDiff();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
}
}
运行结果:
开闭原则:一个软件实体应当对扩展开放,对修改封闭
上边的实例,必须通过修改客户端代码中静态方法的参数来更换具体产品对象,客户端代码需要重新编译,这对于客户端而言,违背了开闭原则。
下面介绍一种常用的解决方案,利用App.config配置文件的方式,提高系统的灵活性。只需要添加配置文件并更改相关参数即可,不要重新编译程序。
需要通过Nuget添加如下引用:
App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
</startup>
<appSettings>
<add key="Product" value="B" />
</appSettings>
</configuration>
调用方法:
using System;
using System.Configuration;//必须添加的引用
namespace ConsoleApp1
{
//其余代码省略,同上
class Program
{
static void Main(string[] args)
{
//客户端调用
var type = ConfigurationManager.AppSettings["product"];
Product productA = Factory.GetProduct(type);
//var productA = Factory.GetProduct("A");
productA.MethodSame();
productA.MethodDiff();
Console.ReadLine();
}
}
}
运行结果:
通过更改App.config中如下行的代码,即可调用不同的产品。
<add key="Product" value="B" />
有时为了简化简单工厂模式,可以将抽象产品类和工厂类合并,将静态工厂方法移到抽象产品类中,根据不同的参数创建不同类型的产品子类对象,这种方法在很多类库和框架中也广泛存在。
实例【配置文件 + 合共抽象产品类和工厂类】:
using System;
using System.Configuration;
namespace ConsoleApp1
{
/// <summary>
/// 具体工厂类A
/// </summary>
public class ConcreteProduceA : Product
{
// 实现业务方法
public override void MethodDiff()
{
Console.WriteLine("具体产品A处理业务方法");
}
}
/// <summary>
/// 具体工厂类B
/// </summary>
public class ConcreteProduceB : Product
{
// 实现业务方法
public override void MethodDiff()
{
Console.WriteLine("具体产品B处理业务方法");
}
}
/// <summary>
/// 合共抽象产品类和工厂类
/// </summary>
public abstract class Product
{
// 静态工厂方法
public static Product GetProduct(string arg)
{
Product product = null;
switch (arg)
{
case "A":
product = new ConcreteProduceA();
break;
case "B":
product = new ConcreteProduceB();
break;
default:
throw new ArgumentException(message: "Invalid arg value");//If the arg is not "A" or "B",throw an exception.
}
return product;
}
// 所有产品类的公共业务方法
public void MethodSame()
{
Console.WriteLine("处理公共业务方法");
}
// 声明抽象业务方法
public abstract void MethodDiff();
}
class Program
{
static void Main(string[] args)
{
//客户端调用
var type = ConfigurationManager.AppSettings["product"];
Product productA = Product.GetProduct(type);
productA.MethodSame();
productA.MethodDiff();
Console.ReadLine();
}
}
}
以上的核心代码:
/// <summary>
/// 合共抽象产品类和工厂类
/// </summary>
public abstract class Product
{
// 静态工厂方法
public static Product GetProduct(string arg)
{
Product product = null;
switch (arg)
{
case "A":
product = new ConcreteProduceA();
break;
case "B":
product = new ConcreteProduceB();
break;
default:
throw new ArgumentException(message: "Invalid arg value");//If the arg is not "A" or "B",throw an exception.
}
return product;
}
// 所有产品类的公共业务方法
public void MethodSame()
{
Console.WriteLine("处理公共业务方法");
}
// 声明抽象业务方法
public abstract void MethodDiff();
}
参考文章:
https://blog.51cto.com/u_11071029/5072340
https://blog.csdn.net/baidu_35536188/article/details/109575787