需求
開披薩店,披薩有很多種豁跑,披薩店也可以有很多個(gè)分店
目的
對(duì)修改關(guān)閉廉涕,針對(duì)接口編程,不針對(duì)實(shí)現(xiàn)編程
簡(jiǎn)單工廠
披薩
public abstract class Pizza
{
String name;
String dough;// 面團(tuán)
String sauce;// 醬
ArrayList<String> toppings = new ArrayList<String>();// 澆在披薩上的
public String getName()
{
return name;
}
// 準(zhǔn)備
public void prepare()
{
System.out.println("Prepare " + name);
System.out.println("Tossing dough...");
System.out.println("Adding sauce...");
System.out.println("Adding toppings: ");
for (String topping : toppings)
{
System.out.println(" " + topping);
}
}
// 烘烤
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()
{
// 顯示披薩名稱和配料
StringBuffer display = new StringBuffer();
display.append("---- " + name + " ----\n");
display.append(dough + "\n");
display.append(sauce + "\n");
for (String topping : toppings)
{
display.append(topping + "\n");
}
return display.toString();
}
}
// ------------------------------------------------------------------------
// 蛤蜊披薩
public class ClamPizza extends Pizza
{
public ClamPizza()
{
name = "Clam Pizza";
dough = "Thin crust";
sauce = "White garlic sauce";
toppings.add("Clams");
toppings.add("Grated parmesan cheese");
}
}
<br />
<br />
披薩店
public class PizzaStore
{
SimplePizzaFactory factory; // 披薩店接收一個(gè)披薩制造工廠
public PizzaStore(SimplePizzaFactory factory)
{
this.factory = factory;
}
// 客戶可以訂披薩
public Pizza orderPizza(String type)
{
Pizza pizza;
pizza = factory.createPizza(type); // 交給工廠來創(chuàng)建披薩
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
<br />
<br />
披薩工廠
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;
}
}
<br />
<br />
測(cè)試
public static void main(String[] args)
{
// 創(chuàng)建個(gè)工廠
SimplePizzaFactory factory = new SimplePizzaFactory();
// 創(chuàng)建個(gè)披薩店
PizzaStore store = new PizzaStore(factory);
// 預(yù)訂披薩艇拍,披薩店使用工廠創(chuàng)建披薩狐蜕,然后披薩店自己處理披薩的烘烤、切片卸夕、裝盒
Pizza pizza = store.orderPizza("cheese");
System.out.println("We ordered a " + pizza.getName() + "\n");
System.out.println(pizza);
pizza = store.orderPizza("veggie");
System.out.println("We ordered a " + pizza.getName() + "\n");
System.out.println(pizza);
}
簡(jiǎn)單工廠的問題和好處
- 把創(chuàng)建披薩的代碼放到了一個(gè)地方层释,SimplePizzaFactory的客戶可以有很多,不只是orderPizza快集,可以是菜單什么的贡羔,通過工廠獲取價(jià)格
- 可以使用靜態(tài)方法來替代工廠,成為靜態(tài)工廠个初,但是缺點(diǎn)是沒法通過繼承來改變行為
<br />
<br />
工廠方法乖寒,重做披薩店
由于很多加盟商,在不同的地區(qū)開店院溺,因此需要配合當(dāng)?shù)氐目谖堕灌遥孕枰ㄖ婆_店
披薩店重做
public abstract class PizzaStore
{
// 這個(gè)方法就像一個(gè)工廠,由子類決定如何制造披薩
public abstract Pizza createPizza(String item);
public Pizza orderPizza(String type)
{
// 創(chuàng)建披薩珍逸,由子類來決定逐虚,你要?jiǎng)?chuàng)建的是什么樣的披薩
Pizza pizza = createPizza(type);
System.out.println("--- Making a " + pizza.getName() + " ---");
// 加工,由于披薩的風(fēng)味和制作方法各有不同弄息,因此也交給子類來決定痊班,從而達(dá)到解耦的目的
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
// 開店
public class ChicagoPizzaStore extends PizzaStore
{
public Pizza createPizza(String item)
{
if (item.equals("cheese"))
{
return new ChicagoStyleCheesePizza();
} else if (item.equals("veggie"))
{
return new ChicagoStyleVeggiePizza();
} else if (item.equals("clam"))
{
return new ChicagoStyleClamPizza();
} else if (item.equals("pepperoni"))
{
return new ChicagoStylePepperoniPizza();
} else
return null;
}
}
披薩可以自己定義加工自己的方式
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");
}
}
工廠方法模式的定義
定義了一個(gè)創(chuàng)建對(duì)象的接口,由子類決定要?jiǎng)?chuàng)建的對(duì)象是哪一個(gè)摹量,工廠方法讓類實(shí)例化推遲到了子類中涤伐。
設(shè)計(jì)原則 6 :依賴倒置原則
要依賴抽象馒胆,不要依賴具體類。
不能讓高層組件依賴于具體的低層組件凝果,在這個(gè)例子中祝迂,披薩店就是高層,披薩就是低層器净,而不管對(duì)于高層還是低層型雳,都應(yīng)該依賴于抽象,而不要依賴于具體的抽象類山害。
比如上面的PizzaStore依賴的就是Pizza這個(gè)抽象纠俭,而不是依賴于具體的某個(gè)Pizza子類
如何應(yīng)用此原則
- 變量不可以持有具體類的引用,比如使用new得到具體類的實(shí)例浪慌,可以使用工廠方法
- 類不可以派生于具體類冤荆,需要派生于一個(gè)抽象,就是接口或抽象類
- 不要覆蓋父類中已實(shí)現(xiàn)的方法权纤,父類中的方法應(yīng)該被所有的子類共享
<br />
<br />
抽象工廠
現(xiàn)在不僅披薩店要定制钓简,制作披薩的原料也要定制会宪,因此需要不同的原料工廠
原料工廠
// 原料工廠伴澄,每種原料都對(duì)應(yīng)一種創(chuàng)建的方法,抽象化奕短,交給子類決定使用什么原料
public interface PizzaIngredientFactory
{
public Dough createDough();
public Sauce createSauce();
public Cheese createCheese();
public Veggies[] createVeggies();
public Pepperoni createPepperoni();
public Clams createClam();
}
// 芝加哥原料工廠古掏,指定要使用哪些原料
public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory
{
public Dough createDough()
{
return new ThickCrustDough();
}
public Sauce createSauce()
{
return new PlumTomatoSauce();
}
public Cheese createCheese()
{
return new MozzarellaCheese();
}
public Veggies[] createVeggies()
{
Veggies veggies[] =
{ new BlackOlives(), new Spinach(), new Eggplant() };
return veggies;
}
public Pepperoni createPepperoni()
{
return new SlicedPepperoni();
}
public Clams createClam()
{
return new FrozenClams();
}
}
原料接口损话,同一種原料的生產(chǎn)之類的可能每個(gè)地區(qū)都不一樣
public interface Cheese
{
public String toString();
}
public class MozzarellaCheese implements Cheese
{
public String toString()
{
return "Shredded Mozzarella";
}
}
// 省略其他原料定義
披薩
public abstract class Pizza
{
public String name;
public Dough dough;
public Sauce sauce;
public Veggies veggies[];
public Cheese cheese;
public Pepperoni pepperoni;
public Clams clam;
public abstract void prepare();
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 void setName(String name)
{
this.name = name;
}
public 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();
}
}
public class CheesePizza extends Pizza
{
PizzaIngredientFactory ingredientFactory;
// 由商店決定要用哪個(gè)工廠的原料
public CheesePizza(PizzaIngredientFactory ingredientFactory)
{
this.ingredientFactory = ingredientFactory;
}
public void prepare()
{
System.out.println("Preparing " + name);
// 只要是工廠就可以,不在乎具體是誰(shuí)
dough = ingredientFactory.createDough();
sauce = ingredientFactory.createSauce();
cheese = ingredientFactory.createCheese();
}
}
披薩店
父類不需要更改了冗茸,由子類自己決定自己的店需要的原料工廠
public class ChicagoPizzaStore extends PizzaStore
{
protected Pizza createPizza(String item)
{
Pizza pizza = null;
// 指定工廠
PizzaIngredientFactory ingredientFactory = new ChicagoPizzaIngredientFactory();
if (item.equals("cheese"))
{
pizza = new CheesePizza(ingredientFactory);
pizza.setName("Chicago Style Cheese Pizza");
} else if (item.equals("veggie"))
{
pizza = new VeggiePizza(ingredientFactory);
pizza.setName("Chicago Style Veggie Pizza");
} else if (item.equals("clam"))
{
pizza = new ClamPizza(ingredientFactory);
pizza.setName("Chicago Style Clam Pizza");
} else if (item.equals("pepperoni"))
{
pizza = new PepperoniPizza(ingredientFactory);
pizza.setName("Chicago Style Pepperoni Pizza");
}
return pizza;
}
}
抽象工廠的定義
提供一個(gè)接口席镀,用于創(chuàng)建相關(guān)的,或者依賴的家族夏漱,而不需要明確指定具體類
工廠方法和抽象工廠的比較
抽象工廠的方法,經(jīng)常以工廠方法的方式呈現(xiàn)
工廠方法使用的是繼承顶捷,繼承一個(gè)工廠方法去創(chuàng)建對(duì)象挂绰,客戶只需要知道它的父抽象類型即可。抽象工廠使用的是組合服赎,在繼承到方法創(chuàng)建對(duì)象后葵蒂,然后將相關(guān)的產(chǎn)品組合起來.
抽象工廠由于是大的產(chǎn)品家族,后續(xù)要是加入新的類型重虑,就需要更改接口践付,工作量會(huì)很大
總之,需要產(chǎn)品族的用抽象工廠缺厉,如果只是單一的永高,可以用工廠方法