设计模式学习--工厂模式(Factory Pattern)
2013年5月30日 设计模式学习记录
什么是工厂模式?
工厂模式可分为以下三种类型,需要根据不同需求来决定使用哪一种模式:
1. 简单工厂(不是真正意义上的设计模式)
2. 工厂方法(定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类实例化推迟到子类)
3. 抽象工厂(提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类)
面向对象原则:
多用组合,少用继承
针对接口编程,不针对实现编程
为交互对象之间的松耦合而努力
类应该对扩展开放,对修改关闭
依赖抽象,不是依赖具体类(新的原则)
要点:
1. 所有的工厂都是用来封装对象的创建。
2. 简单工厂,虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户程序从具体类解耦。
3. 工厂方法使用继承:把对象的创建委托给子类子类实现工厂方法来创建对象。
4. 抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中。
5. 所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合。
6. 工厂方法允许类将实例化延迟到子类进行。
7. 抽象工厂创建相关的对象家族,而不需要依赖它们的具体类。
8. 依赖倒置原则,指导我们避免依赖具体类型,而要尽量依赖抽象。
9. 工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体类编程。
工厂模式应用实例:比萨店
简单工厂实现
看看UML的类图
项目结构:
源代码:
/Pizza.java
package pizzas;
import java.util.ArrayList;
/***
* 抽象pizza类
* @author wwj
*
*/
abstract public class Pizza {
String name;
String dough;
String sauce;
ArrayList toppings = new ArrayList();
public String getName() {
return name;
}
@Override
public String toString() {
StringBuffer display = new StringBuffer();
display.append("----" + name + "----\n");
display.append(dough + "\n");
display.append(sauce + "\n");
for(int i = 0; i < toppings.size(); i++) {
display.append((String)toppings.get(i) + "\n");
}
return display.toString();
}
//准备
public void prepare() {
System.out.println("Preparing " + name);
}
//烘烤
public void bake() {
System.out.println("Baking " + name);
}
//切片
public void cut() {
System.out.println("Cutting " + name);
}
//装箱
public void box() {
System.out.println("Boxing " + name);
}
}
package pizzas;
/**
* 2013/5/25
* @author wwj
*
*/
public class CheesePizza extends Pizza {
@SuppressWarnings("unchecked")
public CheesePizza() {
name = "Cheese Pizza";
dough = "Regular Crust";
sauce = "Marinara Pizza Sauce";
toppings.add("Fresh Mozzarella");
toppings.add("Parmesan");
}
}
package pizzas;
/**
* 2013/5/25
* @author wwj
*
*/
public class ClamPizza extends Pizza {
@SuppressWarnings("unchecked")
public ClamPizza() {
name = "Clam Pizza";
dough = "Thin crust";
sauce = "White garlic sauce";
toppings.add("Clams");
toppings.add("Grated parmesan cheese");
}
}
package pizzas;
/**
* 2013/5/25
* @author wwj
*
*/
public class PepperoniPizza extends Pizza {
@SuppressWarnings("unchecked")
public PepperoniPizza() {
name = "Pepperoni Pizza";
dough = "Crust";
sauce = "Marinara sauce";
toppings.add("Sliced Pepperoni");
toppings.add("Sliced Onion");
toppings.add("Grated parmesan cheese");
}
}
package pizzas;
/**
* 素食pizza
* @author wwj
*
*/
public class VegglePizza extends Pizza {
@SuppressWarnings("unchecked")
public VegglePizza(){
name = "Veggie Pizza";
dough = "Crust";
sauce = "Marinara sauce";
toppings.add("Shredded mozzarella");
toppings.add("Grated parmesan");
toppings.add("Diced onion");
toppings.add("Sliced mushrooms");
toppings.add("Sliced red pepper");
toppings.add("Sliced black olives");
}
}
/SimplePizzaFactory.java
package pizzas;
/**
* 2013/5/27
* @author wwj
* 简单工厂方法
*/
public class SimplePizzaFactory {
public Pizza createPizza(String type) {
Pizza pizza = null;
if(type.equals("cheese")) {
pizza = new CheesePizza();
} else if(type.equals("pepperoni")) {
pizza = new PepperoniPizza();
} else if(type.equals("clam")) {
pizza = new ClamPizza();
} else if(type.equals("veggie")) {
pizza = new VegglePizza();
}
return pizza;
}
}
/PizzaStore
package pizzas;
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;
}
}
/PizzaTestDriver
package pizzas;
/**
* 2013/5/25
* @author wwj
* 简单工厂的测试类
*/
public class PizzaTestDriver {
public static void main(String[] args) {
SimplePizzaFactory factory = new SimplePizzaFactory();
PizzaStore store = new PizzaStore(factory);
Pizza pizza = store.orderPizza("cheese");
System.out.println("We ordered a " + pizza.getName() + "\n");
pizza = store.orderPizza("veggie");
System.out.println("We ordered a " + pizza.getName() + "\n");
}
}
工厂方法模式实现
项目结构:
/Pizza.java
把Pizza声明为抽象的,让所有具体比萨都必须派生自这个类。
package pizzafm;
import java.util.ArrayList;
/**
* 2013/5/25
* @author wwj
*
*/
public abstract class Pizza {
String name; //名称
String dough; //面团类型
String sauce; //一套佐料
ArrayList toppings = new ArrayList();
public 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 < 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 PizzaStore box");
}
public String getName() {
return name;
}
}
package pizzafm;
/**
* 纽约披萨
* @author wwj
*
*/
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");
}
}
package pizzafm;
public class NYStyleClamPizza extends Pizza {
public NYStyleClamPizza() {
name = "NY Style Clam Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
toppings.add("Grated Reggiano Cheese");
toppings.add("Fresh Clams from Long Island Sound");
}
}
package pizzafm;
public class NYStylePepperoniPizza extends Pizza {
public NYStylePepperoniPizza() {
name = "NY Style Pepperoni Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
toppings.add("Grated Reggiano Cheese");
toppings.add("Sliced Pepperoni");
toppings.add("Garlic");
toppings.add("Onion");
toppings.add("Mushrooms");
toppings.add("Red Pepper");
}
}
package pizzafm;
public class NYStyleVeggiePizza extends Pizza {
public NYStyleVeggiePizza() {
name = "NY Style Veggie Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
toppings.add("Grated Reggiano Cheese");
toppings.add("Garlic");
toppings.add("Onion");
toppings.add("Mushrooms");
toppings.add("Red Pepper");
}
}
package pizzafm;
/**
* 芝加哥披萨
* @author wwj
*
*/
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 square slices");
}
}
package pizzafm;
public class ChicagoStyleClamPizza extends Pizza {
public ChicagoStyleClamPizza() {
name = "Chicago Style Clam Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.add("Shredded Mozzarella Cheese");
toppings.add("Frozen Clams from Chesapeake Bay");
}
public void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
package pizzafm;
public class ChicagoStylePepperoniPizza extends Pizza {
public ChicagoStylePepperoniPizza() {
name = "Chicago Style Pepperoni Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.add("Shredded Mozzarella Cheese");
toppings.add("Black Olives");
toppings.add("Spinach");
toppings.add("Eggplant");
toppings.add("Sliced Pepperoni");
}
public void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
package pizzafm;
public class ChicagoStyleVeggiePizza extends Pizza {
public ChicagoStyleVeggiePizza() {
name = "Chicago Deep Dish Veggie Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.add("Shredded Mozzarella Cheese");
toppings.add("Black Olives");
toppings.add("Spinach");
toppings.add("Eggplant");
}
public void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
/PizzaStore.java
此类也是声明为抽象的,实例化比萨的责任由具体的子类来实现
package pizzafm;
/**
* 2013/5/25
* @author wwj
* 让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);
}
package pizzafm;
public class NYPizzaStore extends PizzaStore {
@Override
Pizza createPizza(String type) {
if(type.equals("cheese")){
return new NYStyleCheesePizza();
} else if(type.equals("veggie")) {
return new NYStyleVeggiePizza();
} else if(type.equals("clam")) {
return new NYStyleClamPizza();
} else if(type.equals("pepperoni")){
return new NYStylePepperoniPizza();
} else return null;
}
}
package pizzafm;
public class ChicagoPizzaStore extends PizzaStore {
@Override
Pizza createPizza(String type) {
if(type.equals("cheese")) {
return new ChicagoStyleCheesePizza();
} else if(type.equals("veggie")) {
return new ChicagoStyleVeggiePizza();
} else if(type.equals("clam")) {
return new ChicagoStyleClamPizza();
} else return null;
}
}
/PizzaTestDriver.java
package pizzafm;
/**
* 2013/5/25
* @author wwj
* 工厂模式测试驱动类
*/
public class PizzaTestDriver {
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");
}
}
抽象工厂模式实现
/Pizza.java
package pizzaaf;
public abstract class Pizza {
String name;
Dough dough;
Sauce sauce;
Veggies veggies[];
Cheese cheese;
Pepperoni pepperoni;
Clams clam;
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 official PizzaStore box");
}
void setName(String name) {
this.name = name;
}
String getName() {
return name;
}
public String toString() {
StringBuffer result = new StringBuffer();
result.append("---- " + name + " ----\n");
if (dough != null) {
result.append(dough);
result.append("\n");
}
if (sauce != null) {
result.append(sauce);
result.append("\n");
}
if (cheese != null) {
result.append(cheese);
result.append("\n");
}
if (veggies != null) {
for (int i = 0; i < veggies.length; i++) {
result.append(veggies[i]);
if (i < veggies.length-1) {
result.append(", ");
}
}
result.append("\n");
}
if (clam != null) {
result.append(clam);
result.append("\n");
}
if (pepperoni != null) {
result.append(pepperoni);
result.append("\n");
}
return result.toString();
}
}
package pizzaaf;
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
void prepare() {
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
package pizzaaf;
public class ClamPizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public ClamPizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
@Override
void prepare() {
System.out.println("PreParing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
clam = ingredientFactory.createClam();
}
}
package pizzaaf;
public class PepperoniPizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public PepperoniPizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
void prepare() {
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
veggies = ingredientFactory.createVeggies();
pepperoni = ingredientFactory.createPepperoni();
}
}
package pizzaaf;
public class VeggiePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public VeggiePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
void prepare() {
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
veggies = ingredientFactory.createVeggies();
}
}
/PizzaIngredientFactory.java
package pizzaaf;
/**
* 建造原料工厂
* @author wwj
* 在接口中,每个原料都有一个对应的方法创造该原料
*/
public interface PizzaIngredientFactory {
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();
}
package pizzaaf;
/**
* 创建纽约原料工厂
* @author wwj
*
*/
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();
}
@Override
public Pepperoni createPepperoni() {
return new SlicePepproni();
}
}
package pizzaaf;
/**
* 芝加哥披萨原料工厂
* @author wwj
*
*/
public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
return new ThickCrustDough();
}
@Override
public Sauce createSauce() {
return new plumTomatoSauce();
}
@Override
public Cheese createCheese() {
return new Mozzarella();
}
@Override
public Veggies[] createVeggies() {
Veggies veggies[] = {new BlackOlives(), new Spinach(), new EggPlant()};
return veggies;
}
@Override
public Clams createClam() {
return new FrozenClams();
}
@Override
public Pepperoni createPepperoni() {
return new SlicedPepperoni();
}
}
所有原料接口,一系列产品族
package pizzaaf;
public interface Cheese {
@Override
public String toString();
}
package pizzaaf;
public interface Clams {
@Override
public String toString();
}
package pizzaaf;
public interface Dough {
@Override
public String toString();
}
package pizzaaf;
public interface Sauce {
@Override
public String toString();
}
package pizzaaf;
public interface Veggies {
@Override
public String toString();
}
package pizzaaf;
public interface Pepperoni {
@Override
public String toString();
}
实现Cheese的类
package pizzaaf;
public class Mozzarella implements Cheese {
public String toString() {
return "Shredded Mozzarella";
}
}
package pizzaaf;
public class ReggianoCheese implements Cheese {
public String toString() {
return "Reggiano Cheese";
}
}
实现Clams的类
package pizzaaf;
public class FreshClams implements Clams {
public String toString() {
return "Fresh Clams from Long Island Sound";
}
}
package pizzaaf;
public class FrozenClams implements Clams {
public String toString() {
return "Frozen Clams from Chesapeake Bay";
}
}
实现Sauce的类
package pizzaaf;
public class MarinaraSauce implements Sauce {
public String toString() {
return "Marinara Sauce";
}
}
package pizzaaf;
public class plumTomatoSauce implements Sauce {
public String toString() {
return "Tomato sauce with plum tomatoes";
}
}
实现Veggies的类
package pizzaaf;
public class EggPlant implements Veggies {
public String toString() {
return "Eggplant";
}
}
package pizzaaf;
public class Onion implements Veggies {
public String toString() {
return "Onion";
}
}
package pizzaaf;
public class Spinach implements Veggies {
public String toString() {
return "Spinach";
}
}
package pizzaaf;
public class MushRoom implements Veggies {
public String toString() {
return "Mushrooms";
}
}
实现Pepperoni的类
实现Dough的类
package pizzaaf;
public class ThickCrustDough implements Dough {
public String toString() {
return "ThickCrust style extra thick crust dough";
}
}
package pizzaaf;
public class ThinCrustDough implements Dough {
public String toString() {
return "Thin Crust Dough";
}
}
关于工厂模式已经介绍完,蛮多内容的是吧。
什么时候用工厂方法和抽象方法呢?
来听听它们的告白:
抽象工厂:我是抽象工厂,当你需要创建产品家族和想让制造的相关产品集合起来时,你可以使用我。
工厂方法:我是工厂方法,我可以把你的客户代码从实例化的具体类中解耦。或者如果你目前还不知道将来需要实例化哪些具体类时,也可以用我。我的使用方式简单,只要把握继承成子类,并实现我的工厂方法就行了。