(本文中一些例子和定义均摘自《Head First 设计模式》)
* 感谢 jzkangta 老师的精彩讲解
简单工厂(Simple Factory)模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。
简单工厂模式的主要作用就是由一个工厂对象决定创建出那一种产品类的实例。
是否使用静态方法是需要在一开始就考虑好的,因为使用了静态方法来定义一个简单的工厂的话,就不能通过继承来改变创建方法的行为了。
我们来简单的看一个描述汽车启动,停止的例子:
public static void main(String[] args) ...{
//由工厂来决定创建汽车的类型
Car c = Factory.getCarInstance("Ford");
if(c != null)...{
c.run();
c.stop();
}
else ...{
System.out.println("Donot have this type");
}
}
}
interface Car ... {
public void run();
public void stop();
}
class Benz implements Car ... {
@Override
public void run() ...{
System.out.println("Benz Run......");
}
@Override
public void stop() ...{
System.out.println("Benz stop......");
}
}
class Ford implements Car ... {
@Override
public void run() ...{
System.out.println("Ford Run......");
}
@Override
public void stop() ...{
System.out.println("Ford stop......");
}
}
class Factory ... {
public static Car getCarInstance(String type) ...{
Car c = null;
try ...{
//利用java反射机制来创建实例
c = (Car)Class.forName("cn.gamewave.factory." + type).newInstance();
} catch (Exception e) ...{
e.printStackTrace();
}
return c;
}
}
工厂方法模式(Factory Method Pattern)定义了一个创建对象的接口,但由子类来决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。通过让子类决定该创建的对象是什么,来达到将对象创建过程封装的目的。所有的工厂模式都用来封装对象的创建。
与简单工厂模式之间的区别:
简单工厂模式是建立一个工厂对象来决定创建对象的类型。工厂模式是将各种产品的创建封装在各个不同的创建者(也可以说是生产者)中。简单工厂把全部的事情都在一个地方处理完了,然后工厂方法却是创建了一个框架,让子类决定要如何实现。也可以说是简单工厂方法只允许一个工厂造产品,工厂方法允许不同的工厂都造产品.在工厂方法中产品类与创建者类是平行的,因为它们都是抽象的,都有自己的许多具体的子类,每个子类都有自己的特定实现。单单工厂不具备工厂方法的弹性,如果有新的产品出现,我们将不得不修改创建方法,它不能变更正在创建的产品。
pizza store例子:
我们有许多不同地方的加盟店,也有许多不同口味的pizza
当开一个pizza店的时候,第一件事情,当然是需要有pizza
String name;
String dough;
String sauce;
@SuppressWarnings("unchecked")
ArrayList topping = new ArrayList();
void prepare()...{
System.out.println("preparing" + name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings:");
for(int i = 0; i < topping.size(); i++) ...{
System.out.println(" " + topping.get(i));
}
}
void bake()...{
System.out.println("Bake for 25 minutes at 350");
}
void cut()...{
System.out.println("Cutting the pizza into diagonal slices");
}
void box()...{
System.out.println("Place pizza in offical PizzaStore box");
}
public String getName() ...{
return name;
}
}
抽象化好了pizza后,我们接下来应当考虑的是不同口味的pizza了
@SuppressWarnings("unchecked")
public NYStyleChessPizza() ...{
name = "NY Style Sauce and Cheese Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
topping.add("Grated Reggiano Cheese");
}
}
有了产品后,我们应当考虑开店了。再次将考虑的目标放回到pizza store上
//orderPizza并不知道哪些具体的类参与,这就不同pizza的类型与实际的操作解耦
public Pizza orderPizza(String type) ...{
Pizza pizza;
//创建pizza的时候由具体的pizza store来决定
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
/** *//**
* 仔细看看工厂方法
* abstract Product factoryMethod(String type)
* 工厂方法负责具体对象的创建,并将这种行为封装在具体的子类中
* 已达到超类代码与子类对象创建的解耦
*/
abstract Pizza createPizza(String type);
}
接下来该选择在何处开店,开始加盟吧
//由子类来决定具体创建的实例的类型
@Override
Pizza createPizza(String item) ...{
if(item.equals("cheese")) ...{
return new NYStyleChessPizza();
}
else ...{
return null;
}
}
}
一切就绪,我们也要开始营业了
public static void main(String[] args) ...{
PizzaStore nyStore = new NYPizzaStore();
Pizza pizza = nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a " + pizza.getName());
}
}
这里我们可以看到,无论是增加新的口味 还是 选择另外的地点开新的加盟店都是很方便的。
抽象工厂:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
设想一下新的情况,如果每个地方的原料采购是不同的。
1. 创建原料工厂,负责创建所有原料
public Dough createDough();
public Sauce createSauce();
}
2. 不同的加盟店要实现原料工厂中创建方法
public Dough createDough()...{
return new ThinCrustDough();
}
public Sauce createSauce()...{
return new MarinaraSauce();
}
}
3. 修改Pizza抽象类
public abstract class Pizza ... {
String name;
Dough dough;
Sauce sauce;
@SuppressWarnings("unchecked")
ArrayList topping = new ArrayList();
//设为抽象,不同的Pizza有不同的实现
abstract void prepare();
void bake()...{
System.out.println("Bake for 25 minutes at 350");
}
void cut()...{
System.out.println("Cutting the pizza into diagonal slices");
}
void box()...{
System.out.println("Place pizza in offical PizzaStore box");
}
String getName() ...{
return name;
}
void setName(String name) ...{
this.name = name;
}
}
4. 增加Pizza 的子类,我们发现和以前的 NYStyleChessPizza比较,唯一的差别就是相同品种的Pizza的原料不同,其他的都一样。所以去除掉以前的 NYStyleChessPizza 类,换用新的品种类。
PizzaIngredientFactory ingredientFactory;
public ChessPizza(PizzaIngredientFactory ingredientFactory)...{
this.ingredientFactory = ingredientFactory;
}
void prepare() ...{
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
}
}
5.最后在回到Pizza Store中
@Override
Pizza createPizza(String item) ...{
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
//各地选用各自的原料来制作各地的PIZZA
if(item.equals("cheese")) ...{
pizza = new ChessPizza(ingredientFactory);
pizza.setName("New York Style Chess Pizza");
}
else ...{
return null;
}
return pizza;
}
}
6. 我们来定一个pizza看看
public static void main(String[] args) ...{
PizzaStore nyPizzaStore = new NYPizzaStore();
nyPizzaStore.orderPizza("cheese");
}
}
工厂模式与抽象工厂模式的区别:
1.抽象工厂模式与工厂方法模式的最大区别就在于,工厂方法模式针对的是一个产品等
级结构;而抽象工厂模式则需要面对多个产品等级结构。
2.抽象工厂一般用于创建一个产品家族,缺点就是当增加新类型的时候就要改变接口了。
3.工厂模式是面向产品的,也就是说有多少种产品,就会创造出多少个平行的工厂
抽象工厂模式是面向产品结构的,当所有的产品都有相同的机构的时候,有多少种结构就有多少种工厂,对应的工厂生产对应的产品.而这所有的工厂又同是在同一个工厂等级结构中.