简单工厂模式的弊端
使用简单工厂模式设计系统,在每次增加新的对象时除了需要新增一个类型以外,还需修改工厂类的代码,违背了开闭原则,而工厂方法模式作为简单工厂模式的延申,恰好弥补的简单工厂模式的缺陷。
工厂方法模式
对简单工厂模式加以修改,不再提供一个工厂类负责所有对象的创建,而是先定义一个抽象的工厂基类,将具体对象的创建过程交给专门的工厂子类去完成,每个工厂子类都继承自抽象工厂类,且实现抽象工厂类中声明的方法。使用工厂方法模式可以在出现新的产品时不修改原有的代码,通过新增一个具体的工厂类负责创建该新产品的实例即可,符合开闭原则。
工厂方法模式的定义:定义一个创建对象的接口,但是让子类决定实例化哪一个对象。工厂方法模式让一个类的实例化延迟到其子类。
工厂方法模式的结构
- 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();
}
运行结果
如果新增产品对象,使用工厂方法模式需要做什么?
- 创建新的具体产品类继承抽象产品
- 创建新的具体工厂类继承抽象工厂并实现其方法返回新的产品对象
- 修改配置文件,用新增的具体工厂类名替换原有的工厂类名即可
- 编译新增的具体产品类和新增的具体工厂类,原有代码无需修改,符合开闭原则
工厂方法的隐藏
隐藏工厂方法可以进一步简化开发人员对工厂方法的使用,在工厂类中直接调用产品类的业务方法,使用时无需调用工厂方法创建对象,便是工厂方法隐藏,实例代码如下:
//修改后的抽象工厂类
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();
}
工厂方法模式总结
优点
- 开发人员只需关心产品对应的工厂,无需关心创建细节,对象的创建和使用分离。
- 加入新产品时,无需修改抽象工厂和抽象产品提供的接口,无需修改原有的代码,只要添加新的产品类和对应的具体工厂类即可,系统可扩展性良好,完全符合开闭原则。
缺点
- 在添加新产品时,需要编写新的具体产品类和具体工厂类,使得类的个数成对增加,增加了系统的复杂度,更多的类需要编译和运行。
- 需要引入抽象层,一定程度增加了系统的抽象性和理解难度。
什么时候使用?
- 使用时不需要知道具体产品类名,只需知道对应的工厂就可以,具体产品对象由对应的工厂负责创建,可将具体工厂类的类名存储在配置文件中。
- 通过子类决定创建的具体对象,抽象工厂只提供接口,子类决定具体创建什么对象,利用面向对象的多态性和里氏代换原则,在运行时,子类对象将覆盖父类对象,使得系统更加容易扩展,增加灵活性。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。