一、简介
什么是简单工厂模式?
在现实生活中,工厂是负责生产产品的。在设计模式中,可以简单类比为:简单工厂模式负责生产对象的一个类。
我们平常编程中,当使用”new”关键字创建一个对象时,此时该类就依赖与这个对象,也就是他们之间的耦合度高,当需求变化时,我们就不得不去修改此类的源码。如果需求变化不多,项目开发人员不多,项目较小,那么这样的修改是可行的,但是当修改的代价较大时,应该尽量避免这种修改,并且能获得更好的兼容性。
此时我们可以运用面向对象(OO)的很重要的原则去解决这一的问题,该原则就是——封装改变。既然要封装改变,自然也就要找到改变的代码,然后把改变的代码用类来封装。这样的一种思路也就是我们简单工厂模式的实现方式了。
二、示例
这里给出一个是否使用简单工厂的区别代码示例,示例也可以在我的GitHub中看到
2.1 工厂类定义
GPS和IMU这两个类是最简单的类了。
加上抽象出的接口IEquip,以及简单工厂类EquipSimpleFactory,就构成了一个简单工厂模式下的类定义。
不用接口IEquip也行,不过那样在调用方法对具体产品进行处理时,需要对每个产品都写一个函数。
public interface IEquip
{
string GetName();
}
public class EquipSimpleFactory
{
private static IEquip factory = null;
public static IEquip CreateFactory(string name)
{
switch (name)
{
case "gps":
factory = new Gps();
break;
case "imu":
factory = new IMU();
break;
default:
throw new NotImplementedException();
}
return factory;
}
}
public class Gps : IEquip
{
public string GetName()
{
return nameof(Gps);
}
}
public class IMU : IEquip
{
public string GetName()
{
return nameof(IMU);
}
}
2.2 不使用设计模式的调用
如果不使用设计模式,那么如果要调用其中一个类,可能的写法如下所示。可以看到,每个不同的类,都需要做判断。如果需要修改,每个部分都是独立的,需要逐一修改,比较麻烦。
private void button2_Click(object sender, EventArgs e)
{
string className = "gps";
button2_NoEncapsulation(className);
className = "imu";
button2_NoEncapsulation(className);
}
/// <summary>
/// 如果不用简单工厂
/// </summary>
/// <param name="str1"></param>
private void button2_NoEncapsulation(string className)
{
string str1 = "";
if (className == "gps")
{
Gps e1 = new Gps();
str1 = e1.GetName();
Invoke(new show(showTextbox), new object[] { str1 });
}
else
{
IMU e2 = new IMU();
str1 = e2.GetName();
Invoke(new show(showTextbox), new object[] { str1 });
}
}
2.3 使用简单工厂的调用
好处是显而易见的,由于做了抽象,调用时候完全统一,即便后续需要增加新的东西,调用该类的业务代码也不需要进行修改,而是把修改的工作提前到了类定义中。
private void button2_Click(object sender, EventArgs e)
{
string className = "gps";
button2_Encapsulation(className);
className = "imu";
button2_Encapsulation(className);
}
/// <summary>
/// 如果用简单工厂
/// </summary>
/// <param name="className"></param>
private void button2_Encapsulation(string className)
{
IEquip e3 = EquipSimpleFactory.CreateFactory(className);
string str1 = e3.GetName();
Invoke(new show(showTextbox), new object[] { str1 });
}
三、优缺点和应用场景
看完简单工厂模式的实现之后,肯定会有这样的疑惑(因为我学习的时候也有)——这样我们只是把变化移到了工厂类中罢了,变化点在于:
没应用简单工厂模式之前,修改的是客户类;
现在需要修改工厂类中的方法(也就是多加case语句,)
我首先要说:对的,这个就是简单工厂模式的缺点所在(这个缺点后面介绍的工厂方法可以很好地解决),然而,简单工厂模式与之前的实现也有它的优点。
3.1 优点
- 1、简单工厂模式解决了客户端直接依赖于具体对象的问题,客户端可以消除直接创建对象的责任,而仅仅是消费产品。简单工厂模式实现了对责任的分割;
- 2、简单工厂模式也起到了代码复用的作用,因为之前的实现中,调用时需要对每个类创建自己的逻辑,而逻辑是容易出现问题的地方,也是需要测试的地方。使用简单工厂,复用了逻辑代码,减少了修改问题。(同时这点也是简单工厂方法的缺点——因为工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都会受到影响,也没什么不好理解的,就如事物都有两面性一样道理);
3.2 缺点
虽然上面已经介绍了简单工厂模式的缺点,下面还是总结下简单工厂模式的缺点:
- 1、工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都会受到影响;
- 2、系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,这样就会造成工厂逻辑过于复杂;
3.3 应用场景
了解了简单工厂模式之后的优缺点之后,我们之后就可以知道简单工厂的应用场景了:
- 1、当工厂类负责创建的对象比较少时可以考虑使用简单工厂模式;
- 2、客户如果只知道传入工厂类的参数,对于如何创建对象的逻辑不关心时可以考虑使用简单工厂模式;