1、简单工厂
某比萨店订单可能是这么样的:
Pizza orderPizza(String type){
Pizza pizza;
if(type.equals("cheese"))
pizza=new CheezePizza();
else if(type.equals("clam"))
pizza=new ClamPizza();
else if(type.equals("veggie"))
pizza=new VeggiePizza();
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
if语句没有对修改封闭,比萨菜单改变,这里就必须一改再改。
所以,封装创建对象的代码,我们称这个新对象为 工厂。
建立一个简单比萨工厂:
public class SimplePizzaFactory {
public Pizza createPizza(String type){
Pizza pizza=null;
if(type.equals("cheese"))
pizza=new CheezePizza();
else if (type.equals("clam")) {
pizza=new ClamPizza();
}else if (type.equals("veggie")) {
pizza=new VeggiePizza();
}
return pizza;
}
}
重做PizzaStore类:
public class PizzaStore {
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory){
this.factory=factory;
}
public Pizza orderPizza(String type){
Pizza pizza;
pizza=factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
2、工厂模式
现在有加盟比萨店,你希望加盟店能利用你的代码,好让比萨店的流程能一致不变。
其中一家加盟店希望工厂能制造NY风味的Pizza,另一家则是Chicago风味的Pizza。
我们可以利用SimplePizzaFactory写出两种不同的工厂,这是一种做法。
但是我想要多一些质量控制,加盟店采用自创的流程。。。
把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;
}
protected abstract Pizza createPizza(String type);
}
public class NYPizzaStore extends PizzaStore{
protected Pizza createPizza(String type){
if(type.equals("cheese"))
return new NYStyleCheesePizza();
//其他
else return null;
}
}
public class ChicagoPizzaStore extends PizzaStore{
protected Pizza createPizza(String type){
if(type.equals("cheese"))
return new ChicagoStyleCheesePizza();
//其他
else return null;
}
}
关于Pizza本身:
import java.util.ArrayList;
public abstract class Pizza {
String name;
String dough;
String sauce;
ArrayList toppings=new ArrayList();
public void prepare(){
System.out.println("Preparing "+getName());
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings: ");
for(int i=0;i<toppings.size();i++)
System.out.println(" "+toppings.get(i));
}
public void bake(){
System.out.println("Bake for 25 minutes at 350");
}
public void cut(){
System.out.println("Cutting the pizza into diagonal slices");
}
public void box(){
System.out.println("Place pizza in official PazzaStore box");
}
public String getName(){
return name;
}
}
public class ChicagoStyleCheesePizza extends Pizza{
public ChicagoStyleCheesePizza(){
name="Chicago Style Deep Dish Cheese Pizza";
dough="Extra Thick Crust Dough";
sauce="Plum Tomato Sauce";
toppings.add("Shredded Mozzarella Cheese");
}
public void cut(){
System.out.println("Cutting the pizza into the square slices");
}
}
public class NYStyleCheesePizza extends Pizza{
public NYStyleCheesePizza(){
name="NY Style Sauce and Cheese Pizza";
dough="Thin Crust Dough";
sauce="Marinara Sauce";
toppings.add("Grated Reggiano Cheese");
}
}
来吃些Pizza吧:
public class PizzaTest {
public static void main(String []args){
PizzaStore nyStore=new NYPizzaStore();
PizzaStore chicagoStore=new ChicagoPizzaStore();
Pizza pizza=nyStore.orderPizza("cheese");
System.out.println("Ethan ordered a "+pizza.getName()+"\n");
pizza=chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a "+pizza.getName()+"\n");
}
}
Preparing NY Style Sauce and Cheese Pizza
Tossing dough...
Adding sauce...
Adding toppings:
Grated Reggiano Cheese
Bake for 25 minutes at 350
Cutting the pizza into diagonal slices
Place pizza in official PazzaStore box
Ethan ordered a NY Style Sauce and Cheese Pizza
Preparing Chicago Style Deep Dish Cheese Pizza
Tossing dough...
Adding sauce...
Adding toppings:
Shredded Mozzarella Cheese
Bake for 25 minutes at 350
Cutting the pizza into the square slices
Place pizza in official PazzaStore box
Joel ordered a Chicago Style Deep Dish Cheese Pizza
工厂方法模式通过让子类决定创建的对象是什么,来达到将对象创建的过程封装的目的。
设计原则:依赖抽象,不要依赖具体类
变量不可以持有具体类的引用
不要让类派生自具体类
不要覆盖基类中已实现的方法
3、抽象工厂
为确保每家加盟店都是用高质量的原料,你打算建造一家生产原料的工厂,并运送到各家加盟店。
对于NY和Chicago,你准备了两组不同的原料。
建造原料工厂:
public interface PizzaIngredientFactory {
public Dough creatDough();
public Sauce createSauce();
public Cheese createCheese();
}
创建纽约原料工厂:
public class NYPizzaIngredientFactory implements PizzaIngredientFactory{
@Override
public Dough creatDough() {
// TODO Auto-generated method stub
return new ThinCrustDough();
}
@Override
public Sauce createSauce() {
// TODO Auto-generated method stub
return new MarinaraSauce();
}
@Override
public Cheese createCheese() {
// TODO Auto-generated method stub
return new ReggianoCheese();
}
}
重做比萨:
public abstract class Pizza {
String name;
Dough dough;
Sauce sauce;
Cheese cheese;
abstract void prepare();
void bake(){
System.out.println("Bake for 25 minutes at 250");
}
void cut(){
System.out.println("Cutting the pizza into diagnoal slices");
}
void box(){
System.out.println("Place pizza in official PizzaStore box");
}
void setName(String name){
this.name=name;
}
String getName(){
return name;
}
}
public class CheesePizza extends Pizza{
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory){
this.ingredientFactory=ingredientFactory;
}
@Override
void prepare() {
// TODO Auto-generated method stub
System.out.println("Preparing "+name);
dough=ingredientFactory.creatDough();
sauce=ingredientFactory.createSauce();
cheese=ingredientFactory.createCheese();
}
}
比萨店:
public class NYPizzaStore extends PizzaStore{
@Override
protected Pizza createPizza(String type) {
// TODO Auto-generated method stub
Pizza pizza=null;
PizzaIngredientFactory ingredientFactory=new NYPizzaIngredientFactory();
if(type.equals("cheese")){
pizza=new CheesePizza(ingredientFactory);
pizza.setName("NY style cheese pizza");
}
//...
return pizza;
}
}
来看下流程:
首先需要一个纽约比萨店:
PizzaStore nyPizzaStore=new NYPizzaStore();
接受订单:
nyPizzaStore.orderPizza("cheese");
调用createPizza()方法:
Pizza pizza=createPizza("cheese");
原料工厂:
Pizza pizza =new CheesePizza(nyIngredientFactory);
接下来准备比萨,调用prepare()方法,工厂将被要求准备原料:
void prepare(){
dough=factory.createDough();
sauce=factory.createSauce();
cheese=factory.createCheese();
}
最后得到了比萨,接着烘烤,切片,装盒。
抽象工厂模式提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确指定具体类。
4、三者的比较
同一层次的结构用工厂模式,有不同层次的结构就用抽象工厂。
我在网上看到一个很好理解的例子,种蔬菜的问题,一开始只有根菜类蔬菜,就用简单工厂,工人也只关心种萝卜还是白菜,后来引进了茎菜类蔬菜,就用工厂方法模式,工人关心的是种根菜还是茎菜,再后来要种植转基因和非转基因蔬菜,这样就多出来一个层次就用抽象工厂,工人关心的就是种转基因还是非转基因蔬菜了。