工厂方法模式

DoubleJ

简单工厂模式的弊端

使用简单工厂模式设计系统,在每次增加新的对象时除了需要新增一个类型以外,还需修改工厂类的代码,违背了开闭原则,而工厂方法模式作为简单工厂模式的延申,恰好弥补的简单工厂模式的缺陷。

工厂方法模式

对简单工厂模式加以修改,不再提供一个工厂类负责所有对象的创建,而是先定义一个抽象的工厂基类,将具体对象的创建过程交给专门的工厂子类去完成,每个工厂子类都继承自抽象工厂类,且实现抽象工厂类中声明的方法。使用工厂方法模式可以在出现新的产品时不修改原有的代码,通过新增一个具体的工厂类负责创建该新产品的实例即可,符合开闭原则。

工厂方法模式的定义:定义一个创建对象的接口,但是让子类决定实例化哪一个对象。工厂方法模式让一个类的实例化延迟到其子类。

工厂方法模式的结构

image.png

  • Product(抽象产品):定义产品的接口,工厂方法模式所创建所有对象类型的基类。
  • ProductA(具体产品类):实现了抽象产品的接口,由专门的具体工厂类创建,具体产品和具体工厂关系一一对应。
  • Factory(抽象工厂):声明一个Method,返回抽象产品类型。抽象工厂是工厂方法模式的核心,所有具体工厂类都必须实现抽象工厂类的抽象方法,返回具体的产品对象。
  • ProductAFactory(具体工厂):抽象工厂的子类,实现了抽象工厂的方法,返回具体的产品实例。

工厂方法模式的实现

//抽象工厂也可以是接口
abstract class FactoryMethod
{
    public abstract Product Build();
}

 //具体工厂类
class ProductAFactory : FactoryMethod
{
    public override Product Build()
    {
        return new ProductA();
    }
}

// 抽象基类
abstract class Product
{
    public void SameMethod()
    {
        //所有产品的公共方法
        Console.WriteLine("所有产品的公共方法");
    }

    //差异化行为
    public abstract void DiffMethod();
}

//产品A
class ProductA : Product
{
    public override void DiffMethod()
    {
        //这里实现产品A的业务逻辑
        Console.WriteLine("这里实现产品A的业务逻辑");
    }
}
通过配置文件存储具体工厂类名,实现更换新的具体工厂是无需修改源代码
//配置文件
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
    </startup>
  <appSettings>
    <add key="factoryName" value="Factory.ProductAFactory"/>
  </appSettings>
</configuration>

static void Main()
{
    //读取配置文件
    var factoryName = ConfigurationManager.AppSettings["factoryName"];
    var factoryType = Type.GetType(factoryName);
    var factory = Activator.CreateInstance(factoryType) as FactoryMethod;
    var product = factory.Build();
    product.SameMethod();
    product.DiffMethod();
    Console.ReadKey();
}
运行结果

image.png

如果新增产品对象,使用工厂方法模式需要做什么?
  1. 创建新的具体产品类继承抽象产品
  2. 创建新的具体工厂类继承抽象工厂并实现其方法返回新的产品对象
  3. 修改配置文件,用新增的具体工厂类名替换原有的工厂类名即可
  4. 编译新增的具体产品类和新增的具体工厂类,原有代码无需修改,符合开闭原则

工厂方法的隐藏

隐藏工厂方法可以进一步简化开发人员对工厂方法的使用,在工厂类中直接调用产品类的业务方法,使用时无需调用工厂方法创建对象,便是工厂方法隐藏,实例代码如下:

//修改后的抽象工厂类
abstract class FactoryMethod
{
    public abstract Product Build();

    public void DiffMethod()
    {
        var product = this.Build();
        product.DiffMethod();
    }
}

//使用
static void Main()
{
    //读取配置文件
    var factoryName = ConfigurationManager.AppSettings["factoryName"];
    var factoryType = Type.GetType(factoryName);
    var factory = Activator.CreateInstance(factoryType) as FactoryMethod;
    //无需创建,直接使用
    factory.DiffMethod();
    Console.ReadKey();
}

工厂方法模式总结

优点
  1. 开发人员只需关心产品对应的工厂,无需关心创建细节,对象的创建和使用分离。
  2. 加入新产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改原有的代码,只要添加新的产品类和对应的具体工厂类即可,系统可扩展性良好,完全符合开闭原则。
缺点
  1. 在添加新产品时,需要编写新的具体产品类和具体工厂类,使得类的个数成对增加,增加了系统的复杂度,更多的类需要编译和运行。
  2. 需要引入抽象层,一定程度增加了系统的抽象性和理解难度。
什么时候使用?
  1. 使用时不需要知道具体产品类名,只需知道对应的工厂就可以,具体产品对象由对应的工厂负责创建,可将具体工厂类的类名存储在配置文件中。
  2. 通过子类决定创建的具体对象,抽象工厂只提供接口,子类决定具体创建什么对象,利用面向对象的多态性和里氏代换原则,在运行时,子类对象将覆盖父类对象,使得系统更加容易扩展,增加灵活性。
阅读 751
7 声望
2 粉丝
0 条评论
7 声望
2 粉丝
文章目录
宣传栏