前言
烘烤OO的精华,除了new操作符之外,还有更多制造对象的方法。
工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这样,客户程序中关于超类的代码就和子类对象创建代码解耦了。
简单工厂
简单工厂其实不是一个设计模式,反而比较像是一种编程习惯。
工厂factory处理创建对象的细节,一旦有了SimplePizzaFactory,orderPizza()就变成了此对象的客户。
public class SimplePizzaFactory{
public Pizza createPizza(String type){
Pizza pizza = null;
if(type.equals("cheese")){
pizza = new CheesePizza();
}
else{
pizza = new VeggiePizza();
}
return pizza;
}
}
把创建Pizza的代码包装进一个类,当以后实现改变时,只需要修改这个类即可。
public class PizzaStore{
SimplePizzaFactory simplePizzaFactory;
public PizzaStore(SimplePizzaFactory simplePizzaFactory){
this.simplePizzaFactory = simplePizzaFactory;
}
public Pizza orderPizza(String type){
Pizza pizza;
pizza = simplePizzaFactory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
- PizzaStore——这是工厂的“客户“,PizzaStore现在通过SimplePizzaFactory取得Pizza的实例。
- SimplePizzaFactory——这是创建Pizza的”工厂“,唯一用到具体Pizza类的地方。创建方法通常申明为静态。
- Pizza——这是工厂的”产品“ ,把Pizza定义为抽象类,具有一些有用的实现,这些实现可以被覆盖。
- CheesePizza、VeggiePizza、ClamPizza、PepperoniPizza是”具体产品“,每个产品都必须实现Pizza接口。
接下来登场的是两个重量级的模式,它们都是工厂。
”实现一个接口“泛指”实现某个超类型(类或接口)的某个方法“
工厂方法模式
最开始的思路:
NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.orderPizza(“Veggie”);
新的思路:
把加盟店和创建Pizza捆绑在一起的同时又保持一定的弹性。所要做的事情,就是把createPizza()方法放回到PizzaStore中,不过要把工厂方法设置成”抽象方法“,然后为每个区域风味创建一个PizzaStore的子类。
public abstract class PizzaStore{
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
abstract Pizza createPizza(String type);
//在PizzaStore里,“工厂方法”现在是抽象的
}
允许子类做决定:
- 每个子类都会覆盖createPizza方法,同时使用PizzaStore定义的orderPizza()方法。甚至可以把orderPizza()方法声明为final,以防止被子类覆盖。
- PizzaStore的createPizza()是一个抽象方法,所以任何的具体Pizza子类型“必须实现这个方法”
- NYStylePizzaStore的createPizza()方法会建立纽约风味的Pizza。
public class NYPizzaStore extends PizzaStore{
Pizza createPizza(String item){
if(item.equals("cheese")){
return new NYStyleCheesePizza();
}
else return null;
}
}
说明:
- createPizza()返回一个Pizza对象,由子类全权负责该实例化哪个具体的Pizza。
- NYPizzaStore扩展自PizzaStore,所以拥有orderPizza()方法以及其他的方法。
- 我们必须实现createPizza()方法,因为在PizzaStore里它是抽象的
声明一个工厂方法:
public abstract class PizzaStore{
public Pizza orderPizza(String type){
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
protected abstract Pizza createPizza(String type);
}
abstract Product factoryMethod(String type)
- 工厂方法是抽象的,所以依赖子类来处理对象的创建
- 工厂方法必须返回一个产品。超类中定义的方法,通常使用到工厂方法的返回值。
- 工厂方法将客户和实际创建具体产品的代码分割开来。
- 工厂方法可能需要参数,也可能不需要来指定所要的产品。
新版工厂方法订购Pizza
PizzaStore nyPizzaStore = new NYPizzaStore();//纽约披萨店
nyPizzaStore.orderPizza("cheese");//下订单
Pizza pizza = createPizza("cheese");//orderPizza调用create方法
- 最后经过prepare、bake、cut、box处理完成。
public abstract class Pizza {//披萨本身
String name;
String dough;
String sauce;
ArrayList toppings = new ArrayList();
void prepare(){
}
void bake(){
}
void cut(){
}
void box(){
}
public String getName(){
return name;
}
}
public class NYStyleCheesePizza extends Pizza{
public NYStyleCheesePizza(){
name = "NY Style";
dough = "Thin Crust";
sauce = "Marinara";
toppings.add("Reggiano");
}
}
整体认识工厂方法模式
所有工厂模式都用来封装对象的创建,工厂方法模式Factory Method Pattern通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。
我们可以看到,将一个orderPizza()方法和一个工厂方法联合方法,就可以成为一个框架。除此之外,工厂方法将生产知识封装进各个创建者,这样的做法也可以被视为一个框架。
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
Product——所有的产品必须实现这个共同的接口,这样一来,使用这些产品的类就可以引用这个接口,而不是具体类。
Creator——Creator是一个类,它实现了所有操纵产品的方法,但不实现工厂方法。Creator所有的子类必须实现这个抽象的factoryMethod()方法。
抽象工厂模式
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
比萨店的设计变得很棒:具有弹性的架构,而且遵循设计原则。
原料家族:纽约使用一组原料,而芝加哥使用另一组原料……
public interface PizzaIngredientFactory{
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();
}
//如果每个工厂实例内部都有某一种通用的“机制”需要实现,就可以把这个例子改成抽象类。
创建纽约的原料工厂
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{
public Dough createDough(){
return new ThinCrustDough();
}
public Sauce createSauce(){
return new MarinaraSauce();
}
public Cheese createCheese(){
return new ReggianoCheese();
}
public Veggies[] createVeggies(){
Veggies veggies[] = { new Garlic(),new Onion()};
return veggies;
}
public Pepperoni createPepperoni(){
return new SlicedPepperoni();
}
public Clams createClam(){
return new FreshClams();
}
}
重做比萨……
public abstract class Pizza {//披萨本身
String name;
Dough dough;
Sauce sauce;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperoni;
Clams clam;
abstract void prepare();
void bake(){
}
void cut(){
}
void box(){
}
public String getName(){
return name;
}
}
继续重做比萨……
public class CheesePizza extends Pizza{
PizzaIngredientFactory pizzaIngredientFactory;
public CheesePizza(PizzaIngredientFactory pizzaIngredientFactory){
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
void prepare(){
dough = pizzaIngredientFactory.createDough();
sauce = pizzaIngredientFactory.createSauce();
cheese = pizzaIngredientFactory.createCheese();
}
}
再回到比萨店
public class NYPizzaStore extends PizzaStore{
protected Pizza createPizza(String item){
Pizza pizza = null;
PizzaIngredientFactory pizzaIngredientFactory = new NYPizzaIngredientFactory();
if(item.equals("cheese")){
pizza = new CheesePizza(pizzaIngredientFactory);
pizza.setName("New York Style Cheese Pizza");
}
else
return null;
return pizza;
}
}