在GOF中关于Factory Method模式的定义如下:
“Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.”
定义创建对象的接口,但让子类去决定实例化哪个类。工厂方法将类的实例化推迟给子类。
抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。
抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
首先来看一个关于简单工厂的例子:
我们拥有一个抽象的产品:
public abstract float getPrice();
public String getProductType() {
return " Unknown Product " ;
}
}
继承它的子类有: 糖(Sugar) 和 牛奶(Milk):
private float price;
protected Milk(float price) ...{
this.price = price;
}
public float getPrice() ...{
return price;
}
public String getProductType() ...{
return "Milk";
}
}
private float price;
protected Sugar(float price) ...{
this.price = price;
}
public float getPrice() ...{
return price;
}
public String getProductType() ...{
return "Sugar";
}
}
我们以前很容易的依靠直接new的方式来写代码:
Product sugar = new Sugar();
Product milk = new Milk();
但是这种直接new的方式会在"特殊"的时候带来麻烦,比如在toolkit,framework中。对象的创建紧密的和它的类名联系到了一起。为了解决这个问题,人们引入了简单工厂模式,我们建立一座能够生产糖和牛奶的工厂:
pulbic static Product createProduct(String what) ...{
// When sugar is requested, we return sugar:
if (what.equals("Sugar")) ...{
return new Sugar(1.49F);
}
// When milk is needed, we return milk:
else if (what.equals("Milk")) ...{
return new Milk(0.99F);
}
// If the requested Product is not available,
// we produce Milk for a special price.
else ...{
return new Milk(0.79);
}
}
}
有了这样的一个工厂,我们就只需要向发出请求,让它为我们制造产品了。假如我们以后需要添加一种商品(注意这就是需求可能发生的变化)--面包(Bread),我们只需要去添加一个Bread类,让它继承自Product类。然后去修改ProductFactory类中的createProduct方法,加一个条件判断来处理Bread类就可以了。
public static void main(String args[]) ...{
// At first we create a shopping-cart
Product[] cart = new Product[3];
// Shopping!
cart[0] = ProductFactory.createProduct("Milk");
cart[1] = ProductFactory.createProduct("Sugar");
cart[2] = ProductFactory.createProduct("Bread");
}
}
上面的例子中不可避免在每添加一种商品的时候,就需要在createProduct方法的if-else中添加代码。也可以看做是《重构》中所说的一种"坏味道"。再看一个C#中关于Factory Method模式的例子:
using System;
using System.Collections;
namespace DoFactory.GangOfFour.Factory.RealWorld
... {
// MainApp test application
class MainApp
...{
static void Main()
...{
// Note: constructors call Factory Method
Document[] documents = new Document[2];
documents[0] = new Resume();
documents[1] = new Report();
// Display document pages
foreach (Document document in documents)
...{
Console.WriteLine(" " + document.GetType().Name+ "--");
foreach (Page page in document.Pages)
...{
Console.WriteLine(" " + page.GetType().Name);
}
}
// Wait for user
Console.Read();
}
}
// "Product"
abstract class Page
...{
}
// "ConcreteProduct"
class SkillsPage : Page
...{
}
// "ConcreteProduct"
class EducationPage : Page
...{
}
// "ConcreteProduct"
class ExperiencePage : Page
...{
}
// "ConcreteProduct"
class IntroductionPage : Page
...{
}
// "ConcreteProduct"
class ResultsPage : Page
...{
}
// "ConcreteProduct"
class ConclusionPage : Page
...{
}
// "ConcreteProduct"
class SummaryPage : Page
...{
}
// "ConcreteProduct"
class BibliographyPage : Page
...{
}
// "Creator"
abstract class Document
...{
private ArrayList pages = new ArrayList();
// Constructor calls abstract Factory method
public Document()
...{
this.CreatePages();
}
public ArrayList Pages
...{
get...{ return pages; }
}
// Factory Method
public abstract void CreatePages();
}
// "ConcreteCreator"
class Resume : Document
...{
// Factory Method implementation
public override void CreatePages()
...{
Pages.Add(new SkillsPage());
Pages.Add(new EducationPage());
Pages.Add(new ExperiencePage());
}
}
// "ConcreteCreator"
class Report : Document
...{
// Factory Method implementation
public override void CreatePages()
...{
Pages.Add(new IntroductionPage());
Pages.Add(new ResultsPage());
Pages.Add(new ConclusionPage());
Pages.Add(new SummaryPage());
Pages.Add(new BibliographyPage());
}
}
}
上面的例子除了使用Creator(抽象类)外,还有ConcreteCreator(具体类),通过多态性就很好消除了"if-else"泛滥的坏味道。
从上面两个例子可以看出 工厂方法模式和简单工厂模式 的区别:
1.工厂方法模式与简单工厂模式在结构上的
不同
差异不是很明显。工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。
2.工厂方法模式之所以有一个别名叫多态性工厂模式是因为具体工厂类都有共同的接口,或者有共同的抽象父类。
3.应对需求变化的不同:当系统扩展需要添加新的产品对象时,工厂方法模式仅仅需要添加一个具体对象和一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了"开闭原则"。而简单工厂模式在添加新产品对象后不得不修改创建方法,扩展性不好。
4.工厂方法模式退化后可以演变成简单工厂模式。
5.工厂方法模式进一步演化后可以变成抽象工厂模式。(见抽象工厂模式Abstract Factory)