工厂模式的种类分为三种:
- 简单工厂
- 工厂方法
- 抽象工厂
简单工厂模式
看一下head first中披萨的例子:
披萨的简单工厂类SimplePizzaFactory:
public class SimplePizzaFactory {
public Pizza createPizaa(String type) {
Pizza pizza = null;
if(type.equals("cheese")) {
pizza = new CheesePizza();
} else if(type.equals("peoperoi")) {
pizza = new PepperoniPizza();
} else if(type.equals("clam")) {
pizza = new ClamPizza();
}
return pizza;
}
}
披萨店的类PizzaStore:
public class PizzaStore {
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) {
this.factory = factory;
}
public Pizza orderPizza(String type) {
Pizza pizza;
pizza = factory.createPizaa(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
披萨类自然就是包含基本的方法和披萨的一些参数,这里不做展示了,看下主类中的调用:
public class testFactory {
public static void main(String[] args) {
SimplePizzaFactory simplePizzaFactory = new SimplePizzaFactory();
PizzaStore store = new PizzaStore(simplePizzaFactory);
Pizza cheesePizza = store.orderPizza("cheese");//定这个类型的披萨
}
}
head first中提到,准确的说简单工厂更像是编程习惯而不是一个完全的“工厂模式”,其作用就是把创建对象的代码与业务逻辑代码中提出来,使其能复用并且使业务代码更加整洁。
工厂方法
简单工厂中使createPizza方法放在了工厂类中实现,但是当开了几家加盟店的时候这样的方式就不太好处理了,这里来看一下工厂方法如何来解决这个问题。
将顶级的商店PizzaStore设计为抽象类,其中的createPizza方法也为抽象方法,具体实现交给加盟店去实现。
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza;
pizza = factory.createPizaa(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
public abstract Pizza createPizaa(String type);
}
下面我们来开一家中国的分店:
public class CNPizzaStore extends PizzaStore {
@Override
public Pizza createPizaa(String type) {
if(type.equals("cheese")) {
return new CNStyleCheesePizza();
} else if(type.equals("peoperoi")) {
return new CNStyleClamPizza();
} else if(type.equals("clam")) {
return new CNStylePepperonPizza();
} else {
return null;
}
}
}
主类中店一份中国披萨店的cheese披萨:
public class testFactory {
public static void main(String[] args) {
PizzaStore cnStore = new CNPizzaStore();
Pizza pizza = cnStore.orderPizza("cheese");
System.out.println("i'm going to ordered a " + pizza.getNmae());
}
}
抽象工厂
在之前的基础上我们来重新做披萨
定义披萨原料工厂的接口:
public interface PizzaIngredientFactory {
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Clams createClam();
}
具体的原料工厂(纽约原料工厂):
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
return new ThinCrustDough();
}
@Override
public Sauce createSauce() {
return new MarinaraSauce();
}
@Override
public Cheese createCheese() {
return new ReggianoCheese();
}
@Override
public Veggies[] createVeggies() {
Veggies veggies[] = {new Garlic(), new Onion(), new Mushroom(), new RedPepper() };
return Veggies;
}
@Override
public Clams createClam() {
return new FreshClams();
}
}
芝士披萨:
public public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
return new ThinCrustDough();
}
@Override
public Sauce createSauce() {
return new MarinaraSauce();
}
@Override
public Cheese createCheese() {
return new ReggianoCheese();
}
@Override
public Veggies[] createVeggies() {
Veggies veggies[] = {new Garlic(), new Onion(), new Mushroom(), new RedPepper() };
return Veggies;
}
@Override
public Clams createClam() {
return new FreshClams();
}
}class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
void prepare() {
System.out.println("prepare " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
定义的抽象披萨类Pizza:
public abstract class Pizza {
String name;
Dough dough;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperoni;
Clams clam;
abstract void prepare();
void bake() {
System.out.println("bake");
}
void cut() {
System.out.println("cut");
}
void box() {
System.out.println("boxing");
}
void setName(Strign name) {
this.name = name;
}
String getName() {
return name;
}
public String toString() {
//console
}
}
蛤蜊披萨:
public class ClamPizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public ClamPizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
void prepare() {
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
clam = ingredientFactory.createClam();
}
}
纽约披萨店:
public class NYPizzaStore extends PizzaStore {
@Override
public Pizza createPizaa(String item) {
Pizza pizza = null;
PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
if(item.equals("cheese")) {
pizza = new CheesePizza(ingredientFactory);
pizza.setName("New York Style Cheese Pizza");
} else if (item.equals("veggie")) {
pizza = new VeggiePizza(ingredientFactory);
pizza.setName("New York Style Clam Pizza");
} else if (item.equals("peperoni")) {
pizza = new PepproniPizza(ingredientFactory);
pizza.setName("New York Style")
}
return pizza;
}
}
其实抽象工厂方法中是包含了工厂方法的设计思想,工厂方法设计梗概就是提供一个产品的抽象接口(比如披萨店),然后具体类(例如中国披萨店,美国披萨店)实现自这个接口,之后通过不同的工厂实例来创建不同的产品实例。
抽象工厂就是定义了一个基本的工厂接口,之后的每个工厂的实例都有对应的基本功能。
下面我用大白话来谈谈我的理解:
简单工厂:相当于有个提供生产的工厂,然后你在你自己的店铺中,客人需要什么类型的吃的,你就直接从工厂那边进货就好了,但是问题就在于你目前什么都在从工厂那边拿,你生意做大了之后新增商品的时候不光需要改动自己的店铺还需要改动工厂。
工厂方法:工厂先定下做整件事情的流程,具体怎么做就是交给各个下一级代理工厂去实现,这么做的好处就是容易添加新的类别产品(比如我在中国开了家中国风味的餐厅,有人在美国开了一家美国风味的餐厅等等),缺点是没有一个整体的约束,下一级代理(子类)想怎么干就怎么干。
抽象工厂:这个就类似于连锁店了,总部提供原料和制作方法,下一级代理的各个分部需要严格按照总部的要求来做,只不过这件事情交给下级来做。缺点是在不修改工厂的前提下很难添加新商品。
这里同时也引用一下别人总结的三种工厂方法的区别:
简单工厂 : 用来生产同一等级结构中的任意产品。(对于增加新的产品,无能为力)
工厂方法 :用来生产同一等级结构中的固定产品。(支持增加任意产品)
抽象工厂 :用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)