简单工厂模式

DoubleJ

前言

简单工厂模式属于创建型模式之一,是最常见的设计模式,应用也相当广泛。创建型模式通过让对象的创建和使用分离,使得开发人员在使用对象的时候无需关心对象的创建细节,从而降低系统的耦合度。

创建型模式

该类模式在开发过程中的使用非常频繁,创建型模式关注对象的创建过程,对类的实例化进行了抽象,将模块中对象的创建和使用分离,对外隐藏了对象的创建细节。

简单工厂模式
概念

定义一个工厂类并提供一个方法,工厂方法可以根据参数的不同返回不同的实例,被创建的实例通常都具有相同的父类。由于简单工厂模式中提供的方法通常是静态方法,所以该模式又可以成为静态工厂方法模式。

设计思想

将需要创建的各种不同对象的相关代码封装到不同类中,这些类称为具体的产品类,再抽象和提取它们公共的代码封装在一个抽象产品类中,每一个具体产品类都继承自抽象产品类(属于其子类)。然后提供一个工厂类用于创建各种不同的产品,在工厂类中提供一个创建产品的方法,这个方法支持传参,根据传入的参数不同创建不同的具体产品对象。使用者只需要调用工厂方法并传入对应的参数即可得到相对的产品对象。

结构与实现
结构图

image.png

由结构图可知,简单工厂模式包含3个角色,分别如下:

  • Factory(工厂):工厂类,简单工厂模式的核心,负责实现创建所有产品的内部逻辑。工厂类中提供的静态方法可以直接被外部调用,并且返回抽象产品类型Product
  • Product(抽象产品):它是工厂类所创建的所有产品的基类,封装了各种产品的公共方法
  • ProductA&ProductB(具体产品角色):是简单工厂模式需要创建的目标,每一个具体产品都继承自Product
简单工厂模式的实现
  • 将所有产品的共性移至抽象产品中
// 抽象基类
abstract class Product
{
    public void SameMethod()
    {
        //所有产品的公共方法
        Console.WriteLine("所有产品的公共方法");
    }

    //差异化行为
    public abstract void DiffMethod();
}
  • 创建具体产品类,并实现抽象方法中声明的抽象方法,不同的产品可以有根据需求有不同的实现
//产品A
class ProductA : Product
{
    public override void DiffMethod()
    {
        //这里实现产品A的业务逻辑
        Console.WriteLine("这里实现产品A的业务逻辑");
    }
}
  • 核心工厂类
//工厂类
class Factory
{
    //静态方法
    public static Product GetProduct(string type)
    {
        if (type.Equals("A"))
            return new ProductA();
        else if (type.Equals("B"))
            return new ProductB();

        return null;
    }
}
  • 使用
static void Main()
{
    var product = Factory.GetProduct("A");
    product.SameMethod();
    product.DiffMethod();
    Console.ReadKey();
}
  • 运行结果

image.png

可以发现,如果需要创建其它的具体产品对象,必须修改获取对象时传入的参数才可以实现,且代码需要重新编译,这违背了开闭原则。可以通过读取XML配置解决该问题,修改代码如下:

  • 将需要创建的产品类型保存到配置文件App.config中
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
  <appSettings>
    <add key="productType" value="A"/>
  </appSettings>
</configuration>
  • 修改代码如下
static void Main()
{
    //读取配置文件
    var pType = ConfigurationManager.AppSettings["productType"];
    var product = Factory.GetProduct(pType);
    product.SameMethod();
    product.DiffMethod();
    Console.ReadKey();
}
  • 运行结果

image.png

修改后的代码使用命名空间System.Configuration中ConfigurationManager类的AppSettings属性获取存储在配置文件中的productType,在源码中不包含任何写死的产品类型,如果需要更换创建的具体产品对象,只需修改配置文件中对应的数据即可,无需修改代码,无需重新编译,符合开闭原则。

对象的职责

与一个对象相关的职责通常可分为3种类型:创建对象、使用对象、对象本身的职责。如果一个类中既包含创建对象又包含使用对象,值得注意,这样的设计往往会导致的问题是,如果后续需求变动,需要创建抽象产品的另外一个子类,就必须修改代码。最普遍的方法就是将对象的创建移入工厂中实现,从而达到对象的创建与使用分离,代码解耦。

两个类之间的关系应该尽量简单,如类A类B,应是A创建B,或者A使用B,而不能A既创建B的同时又使用B,让系统更加符合单一职责有利于功能的复用与系统的维护。

是否需要为每一个类都创建一个工厂类?

不需要,如果类很简单,构造过程也不复杂,且不存在太多的变化,便不需要专门为其提供工厂类,直接创建使用即可,否则将会导致工厂泛滥,增加系统的复杂度,效果反而适得其反了。

简单工厂模式的优缺点
优点
  • 可以避免实例化对象的代码在每个使用对象的类中到处都是,因为实例化对象不总是调用构造函数即可,有时还得设置参数,如果这些代码散落在每个创建对象的类中,必然会导致大量的重复代码,而这些类仅仅只需要获得创建好的对象加以使用即可,完全没必要承担创建对象的职责。
  • 对于有多个构造函数的类,引入工厂可以增加代码可读性,如下:
class Rectangle
{
    //创建长方形
    public Rectangle(int w, int h) { }

    //创建正方形
    public Rectangle(int w) { }
}

class RectangleFactory
{
    //创建长方形
    public static Rectangle CreateRectangle(int w, int h)
    {
        return new Rectangle(w, h);
    }

    //创建正方形
    public static Rectangle CreateSquare(int w)
    {
        return new Rectangle(w);
    }
}
  • 实现了对象创建和使用的分离,通过引入配置文件后还可以在不修改客户端代码更换具体对象,增加了系统的灵活性。
缺点
  • 工厂类中包含所有具体产品的创建逻辑,职责过重
  • 使用简单工厂模式会增加系统中类的个数,增加系统复杂度和理解难度
  • 每增加新的对象必须修改工厂类中的逻辑,系统扩展困难
  • 简单工厂模式由于使用了静态方法,将无法针对父类工厂编程,在运行时使用工厂子类覆盖父类,工厂类得不到很好的扩展
什么时候适合使用简单工厂模式?
  1. 工厂类负责创建的对象较少
  2. 开发者只需关心传入工厂的参数,而无需关心对象的创建过程
阅读 398
7 声望
2 粉丝
0 条评论
7 声望
2 粉丝
文章目录
宣传栏