一、什么是工厂设计模式?
根据Gang of Four所述,工厂是用于创建其他对象的对象,就是说工厂是一个带有方法的类,该方法将根据输入的参数创建并返回不同类型的对象。简单地说,如果我们有一个父类和n个子类,并且基于提供的数据,必须创建并返回其中一个子类的对象,那么就需要使用工厂设计模式。
在工厂设计模式中,我们创建一个对象,而不向客户端公开对象创建逻辑,客户端将使用公共接口引用新创建的对象,也就是接口指向某一个实现类。工厂设计模式背后的基本原则是,在运行时,我们根据传递的参数获得对应的对象。
二、理解工厂设计模式
定义接口以及实现类:
public interface Animal
{
string GetAnimalInfo();
}
public class Dog : Animal
{
public string GetAnimalInfo() => "泰迪犬";
}
public class Cat : Animal
{
public string GetAnimalInfo() => "波斯猫";
}
用户需要获取某一个动物的详细信息,如果不用工厂模式,客户端端代码需要如下代码编写方式:
Animal? animal = null;
var typeName = "dog";
if (typeName == "dog")
animal = new Dog();
else if (typeName == "cat")
animal = new Cat();
if (animal is not null)
Console.WriteLine(animal.GetAnimalInfo());
else
Console.WriteLine("Invalid type name");
代码非常简单,拿到类型名称,然后使用 if-else 条件创建适当的 Animal实例,然后调用GetAnimalInfo()获取详细信息。
上述代码实现的问题是什么?
- 首先,客户端类(Program)和相关动物类(Dog、Cat)之间的紧密耦合。
- 其次,如果我们添加一个新的动物类,那么我们也需要通过添加一个额外的 if-else 条件来修改Main方法,这个条件不仅在开发过程中,而且在测试过程中都会产生开销。
而通过使用工厂设计模式就可以克服上述问题。
根据工厂设计模式的定义,工厂设计模式创建对象时不向客户端公开对象创建逻辑,而客户端使用公共接口引用新创建的对象。
Step1:创建工厂类
public class AnimalFactory
{
public static Animal? GetAnimal(string typeName)
{
Animal? animal = null;
if (typeName == "dog")
animal = new Dog();
else if (typeName == "cat")
animal = new Cat();
return animal;
}
}
Step2:修改主方法调用代码
var typeName = "dog";
Animal? animal = AnimalFactory.GetAnimal(typeName);
if (animal is not null)
Console.WriteLine(animal.GetAnimalInfo());
else
Console.WriteLine("Invalid type name");
如上代码所示,客户端需要创建对象,直接调用工厂方法并传入类型名称即可,GetAnimal方法将会创建并返回对应的对象实例给客户端。
三、工厂模式的真实例子
真实世界中,可以说工厂是产品生产的地方,或者说它是一个创造产品的集中地。然后,根据接收到的订单,由工厂交付适当的产品。例如,一个汽车工厂可以生产不同类型的汽车。如果你向汽车工厂订购汽车,那么根据你的要求或规格,工厂将创建适当的汽车,然后交付给你。
同样,在工厂设计模式中。工厂(即类)将根据传入的参数创建和交付产品(即对象)。
四、在实际项目开发中何时使用工厂设计模式?
在由客户端创建对象时指定确切的类名并不是一种好的编程方法,因为这会导致客户端和产品之间的紧密耦合。为了克服这个问题,需要使用工厂设计模式。这种设计模式为客户端提供了的简单机制来创建对象。所以,在遇到如下三种情况时,可考虑使用工厂设计模式:
- 对象需要延申到某一个子类。
- 不知道要创建哪些确切的子类。
- 具体实现将随着时间的推移而变化,而客户端将保持不变。
五、简单工厂模式存在的问题
- 如果我们需要添加任何新的子类 ,那么我们需要在AnimalFactory类的GetAnimal方法中添加一个新的 If else 条件。这违反了开放/封闭设计原则。
- 我们还在工厂类和产品类之间建立了紧密耦合。