一天看完 hf设计模式 中的工厂模式,略微还有点消化不了,于是打算好好探究一下。其实不仅仅是这两个模式之间容易混淆,他们各自的定义也是挺绕的,下面我就仔细回过头翻书+查阅资料,重新捋一捋,研究一下这两个“工厂”。同时还是保持一个开放的心态,设计模式博大精深,很难一文以蔽之,于是《xx小览》系列文章又添新作。
Ps. 鉴于类容过长,我分成两部分来写,第一部分主要是自己对于看 hf设计模式 的总结,第二部分是来自书本和查找资料详细对比二者的不同~~
这是最简单的一种工厂,所做的事情只有一个:
原来所有的 new 操作都在 PizzaStore 主类的 orderPizza 方法中,现在抽离出来,放到简单工厂中,且这个创建方法通常是静态的,见下图也有说。
所以,简单工厂说白了就是一个代理~~
目的也很简单,只是为了如果要添加一种 pizza 的时候不要修改主类就好(也就是所谓的对修改关闭)
PS. 代理,就是不在类中直接定义方法,而使用其它类的成员变量 调用方法(本例中是简单工厂代理了 createPizza() 方法)
PS2. 工厂方法跟模式没有什么联系,即使简单工厂里面也有工厂方法
严格来说,简单工厂方法都不能称作模式,反而更像一种编程习惯,但是经常用,而且总被人误认为一种模式,所以叫做模式了,其实是伪模式~~
详见代码:
////以下源代码顺序:【PizzaStore.java】->【SimplePizzaFactory.java】->【Pizza.java】->【CheesePizza.java】->【main】
///PizzaStore.java
package headfirst.factory.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;
}
}
///SimplePizzaFactory.java
package headfirst.factory.pizzas;
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 VeggiePizza();
}
return pizza;
}
}
///Pizza.java
package headfirst.factory.pizzas;
import java.util.ArrayList;
abstract public class Pizza {
String name;
String dough;
String sauce;
ArrayList toppings = new ArrayList();
public String getName() {
return name;
}
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);
}
public String toString() {
// code to display pizza name and ingredients
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();
}
}
///CheesePizza.java
package headfirst.factory.pizzas;
public class CheesePizza extends Pizza {
public CheesePizza() {
name = "Cheese Pizza";
dough = "Regular Crust";
sauce = "Marinara Pizza Sauce";
toppings.add("Fresh Mozzarella");
toppings.add("Parmesan");
}
}
///PizzaTestDrive.java【main】
package headfirst.factory.pizzas;
public class PizzaTestDrive {
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");
}
}
还是很清晰的~~
终于进入重头戏之一了,关于这个问题呢,hf设计模式 举了一个例子—加盟 pizza 店~~这样就有所谓的 New York Pizza、Chicago Pizza 和 California Pizza,如果用简单工厂,就必须有三个简单工厂来生产, New York Pizza工厂、Chicago Pizza工厂 和 California Pizza工厂,显然不可取。。。
工厂方法的核心:允许子类做决定
就是让 PizzaStore 的各个子类复制定义自己的createPizza() 方法。下面的PizzaStore是抽象类,createPizza() 方法也是抽象的~~
这样做神奇的地方在于,对于super class 的 PizzaStore , 它的方法 orderPizza() 调用了 Pizza 的准备、烘烤、切片、装盒一系列方法,但是 Pizza 却是抽象的,orderPizza() 并不知道是哪些实际的Pizza ,这就是所谓的解耦!
PizzaStore 也会调用它的抽象方法 createPizza() 取得Pizza对象,但是究竟会得到那种Pizza,对他来说也是透明的~~是“顾客”决定到哪个店买,才决定了是哪种 Pizza
上图中的 createPizza() 方法就是一个工厂方法,用来给不同的加盟店继承并去实现。createPizza() 方法的调用是在 orderPizza() 方法中的~~
接下来差不多该上代码了~~
注意,在下面的类中,工厂模式的 Pizza 主类以及 Pizza 的子类和简单工厂模式并没有什么不同~~
////以下源代码顺序:【PizzaStore.java】->【NYPizzaStore.java】->【Pizza.java】->【CheesePizza.java】->【main】
///PizzaStore.java
package headfirst.factory.pizzafm;
public abstract class PizzaStore {
abstract Pizza createPizza(String item);
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
System.out.println("--- Making a " + pizza.getName() + " ---");
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
///NYPizzaStore.java
package headfirst.factory.pizzafm;
public class NYPizzaStore extends PizzaStore {
Pizza createPizza(String item) {
if (item.equals("cheese")) {
return new NYStyleCheesePizza();
} else if (item.equals("veggie")) {
return new NYStyleVeggiePizza();
} else if (item.equals("clam")) {
return new NYStyleClamPizza();
} else if (item.equals("pepperoni")) {
return new NYStylePepperoniPizza();
} else return null;
}
}
///Pizza.java
package headfirst.factory.pizzafm;
import java.util.ArrayList;
public abstract class Pizza {
String name;
String dough;
String sauce;
ArrayList toppings = 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 < toppings.size(); i++) {
System.out.println(" " + toppings.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 official PizzaStore box");
}
public String getName() {
return name;
}
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();
}
}
///NYStyleCheesePizza.java
package headfirst.factory.pizzafm;
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");
}
}
///PizzaTestDrive.java【main】
package headfirst.factory.pizzafm;
public class PizzaTestDrive {
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");
}
}
整个过程是这样的:
工厂模式的创建者类和产品类是平行的类层级~~
另外,这里涉及一个很高逼的原则—依赖倒置原则
要依赖抽象,不要依赖具体类
再具体一点就是以下原则:
1、变量不开源持有具体类的引用。(如果使用new,就会持有具体类的引用,改用工厂方法可以避开这种做法)
2、不要让类派生自具体类。(因为派生自具体类,就会依赖具体类)
3、不要覆盖基类中已实现的方法。(如果基类已实现,就说明不是一个很适合继承的抽象类,基类中已实现的方法,应该由所有子类共享)
工厂模式 over
这个是重中之重了~~
对于抽象工厂模式,hf设计模式 又想了另一个很好的例子,但是这次不只是 NY 或是 Chicago 简单的地域变换(仅仅是地区问题,就可以只使用工厂模式解决),这个例子是关于原料要是统一的工厂发配,但是每个地区的口味不同,原料也不一样~~
注意:以下箭头标注的,每一个地方的原料是固定的,如果这些 sauce 都一样
所以关键在于:
这些 Pizza 都是采用相同的组件制造(有酱料、干酪、蛤蜊。。。),但每个区域对于这些组件有不同的制造(也就是说有 NY 原料工厂、Chicago 原料工厂。。。)
感悟:重点在于,是一组抽象的制造,然后子类继承并实现这一组的new
而每个具体的原料工厂就生产当地必须的原料 即可。
其实说穿了上面这一点,感觉抽象工厂也就差不多了~~
于是。。。。。。。。。。。是时候上源码了~~
特别注意:这个例子里面抽象工厂的 Pizza 类改变比较大,因为 Pizza 的原料是各个地方生产的,所以 Pizza 主类的 prepare() 方法是抽象的,而对于各种 Pizza 子类,实现 prepare() 方法时,也只是简单的使用了下面这句~~
sause = ingredientFactory.createSauce();
Pizza 类根本不关心这些原料,它只关心如何制作。所以 Pizza 和区域原料之间解耦,于是不会出现工厂模式中的类似 NYStyleCheesePizza 的类了。
////以下源代码顺序:【PizzaStore.java】->【NYPizzaStore.java】->【PizzaIngredientFactory.java】->【NYPizzaIngredientFactory.java】->【Pizza.java】->【CheesePizza.java】->【Cheese.java】->【MozzarellaCheese.java】->【main】
///PizzaStore.java(PizzaStore 没什么变化)
package headfirst.factory.pizzaaf;
public abstract class PizzaStore {
protected abstract Pizza createPizza(String item);
public Pizza orderPizza(String type) {
Pizza pizza = createPizza(type);
System.out.println("--- Making a " + pizza.getName() + " ---");
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
///NYPizzaStore.java
package headfirst.factory.pizzaaf;
public class NYPizzaStore extends PizzaStore {
protected Pizza createPizza(String item) {
Pizza pizza = null;
///各地的 PizzaStore 从原料工厂进货,实例化 NY 原料工厂
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 Veggie Pizza");
} else if (item.equals("clam")) {
pizza = new ClamPizza(ingredientFactory);
pizza.setName("New York Style Clam Pizza");
} else if (item.equals("pepperoni")) {
pizza = new PepperoniPizza(ingredientFactory);
pizza.setName("New York Style Pepperoni Pizza");
}
return pizza;
}
}
///PizzaIngredientFactory.java【原料工厂抽象类】
package headfirst.factory.pizzaaf;
public interface PizzaIngredientFactory {
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();
}
///NYPizzaIngredientFactory.java
package headfirst.factory.pizzaaf;
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(), new Mushroom(), new RedPepper() };
return veggies;
}
public Pepperoni createPepperoni() {
return new SlicedPepperoni();
}
public Clams createClam() {
return new FreshClams();
}
}
///Pizza.java【Pizza 抽象类,注意 prepare() 方法是抽象的】
package headfirst.factory.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();
}
}
///CheesePizza.java
package headfirst.factory.pizzaaf;
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
void prepare() {
System.out.println("Preparing " + name);
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
///Cheese.java
package headfirst.factory.pizzaaf;
public interface Cheese {
public String toString();
}
///MozzarellaCheese.java
package headfirst.factory.pizzaaf;
public class MozzarellaCheese implements Cheese {
public String toString() {
return "Shredded Mozzarella";
}
}
///PizzaTestDrive.java【main】
package headfirst.factory.pizzaaf;
public class PizzaTestDrive {
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 + "\n");
pizza = chicagoStore.orderPizza("cheese");
System.out.println("Joel ordered a " + pizza + "\n");
pizza = nyStore.orderPizza("clam");
System.out.println("Ethan ordered a " + pizza + "\n");
pizza = chicagoStore.orderPizza("clam");
System.out.println("Joel ordered a " + pizza + "\n");
}
}
版权声明:欢迎转载,注明出处就好!如果不喜欢请留言说明原因再踩哦,谢谢,我也可以知道原因,不断进步!!
原文地址:http://blog.csdn.net/scythe666/article/details/47304985