步步为营 .NET 设计模式学习笔记 二十四、Factory Method(工厂方法模式)
概述
在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。如何应对这种变化?提供一种封装机制来隔离出“这个易变对象”的变化,从而保持系统中“其它依赖该对象的对象”不随着需求的改变而改变?这就是要说的Factory Method模式了。
意图
定义一个用户创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。
结构图
角色说明:
抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色:BulbCreator与TubeCreator。
抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在上图中,这个角色是Light。
具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
生活中的例子
工厂方法定义一个用于创建对象的接口,但是让子类决定实例化哪个类。压注成型演示了这种模式。塑料玩具制造商加工塑料粉,将塑料注入到希望形状的模具中。玩具的类别(车,人物等等)是由模具决定的。
示例用例图
如果去麦当劳吃汉堡,汉堡的制作过程就是一个工厂方法模式,用例图如下:
代码设计
先创建Hamburger.cs:
1 |
public abstract class Hamburger |
2 |
{ |
3 |
public abstract string BuyHamburger(); |
4 |
} |
再创建CheeseBurger.cs:
1 |
public class CheeseBurger : Hamburger |
2 |
{ |
3 |
public override string BuyHamburger() |
4 |
{ |
5 |
return "你要的是起司汉堡\n" ; |
6 |
} |
7 |
} |
再创建RoastedChickenBurger.cs:
1 |
public class RoastedChickenBurger : Hamburger |
2 |
{ |
3 |
public override string BuyHamburger() |
4 |
{ |
5 |
return "你要的是黄金烤鸡腿堡\n" ; |
6 |
} |
7 |
} |
再创建ConcreteHamburger.cs:
1 |
public class ConcreteHamburger |
2 |
{ |
3 |
public static string ProduceHamburger( string category) |
4 |
{ |
5 |
Assembly assembly = Assembly.Load( "Factory" ); |
6 |
Hamburger hamburger = assembly.CreateInstance( "Factory." + category) as Hamburger; |
7 |
return hamburger.BuyHamburger(); |
8 |
} |
9 |
} |
最后再调用:
01 |
public partial class Run : Form |
02 |
{ |
03 |
public Run() |
04 |
{ |
05 |
InitializeComponent(); |
06 |
} |
07 |
08 |
private void btnRun_Click( object sender, EventArgs e) |
09 |
{ |
10 |
//------------------------------------- |
11 |
rtbResult.AppendText(ConcreteHamburger.ProduceHamburger( "CheeseBurger" )); |
12 |
rtbResult.AppendText(ConcreteHamburger.ProduceHamburger( "RoastedChickenBurger" )); |
13 |
14 |
} |
15 |
16 |
} |
运行结果如下图:
实现要点
1.Factory Method模式的两种情况:一是Creator类是一个抽象类且它不提供它所声明的工厂方法的实现;二是Creator是一个具体的类且它提供一个工厂方法的缺省实现。
2.工厂方法是可以带参数的。
3.工厂的作用并不仅仅只是创建一个对象,它还可以做对象的初始化,参数的设置等。
4.通过继承创建具体产品。很多时候,每一种具体产品对应一个具体的工厂来创建。
5.使用具体工厂类来决定怎么样创建具体产品。调用方并不关心工厂创建的是哪个制作场景,它只用知道工厂给我的是一个产品名称即可。
效果
1.用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。
2.Factory Method模式通过面向对象的手法,将所要创建的具体对象的创建工作延迟到了子类,从而提供了一种扩展的策略,较好的解决了这种紧耦合的关系。
适用性
在以下情况下,适用于工厂方法模式:
1. 当一个类不知道它所必须创建的对象的类的时候。
2. 当一个类希望由它的子类来指定它所创建的对象的时候。
3. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
4.从代码角度来说, 如果我们需要创建一个易变的对象,或是希望对象由子类决定创建哪个对象的时候可以考虑工厂方法。
5.从应用角度来说, 如果我们觉得具体产品的创建不稳定,或者客户端根本无需知道创建哪个具体产品的时候可以使用工厂方法。后者对于框架和工具包软件来说更常见,比如有一个打印类负责打印图纸,我们需要得到一个打印对象,对于调用方来说并不知道要使用超宽打印对象还是普通打印对象,我们可以通过工厂方法使客户端和抽象打印工厂直接沟通,由它来决定具体创建哪个打印对象。
总结
Factory Method模式是设计模式中应用最为广泛的模式,通过本文,相信读者已经对它有了一定的认识。然而我们要明确的是:在面向对象的编程中,对象的创建工作非常简单,对象的创建时机却很重要。Factory Method要解决的就是对象的创建时机问题,它提供了一种扩展的策略,很好地符合了开放封闭原则。