設計模式之Factory——買貨篇
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
今天老婆讓我去市場買一些水果,具體買什麼自己定(哈,老婆放放權了!)。來到市場,我發現主要有一些水果:蘋果(Apple),葡萄(Grape)和鴨梨(Pear)。
到底買什麼好呢?我一陣思量。俗話說:“飯後一隻煙,賽過活神仙。飯後喫蘋果,西施見我躲。”爲了老婆的漂亮,我決定買蘋果。
好,言歸正傳,開始買吧!
主要有以下三種Factory模式:
Simple Factory模式
專門定義一個類來負責創建其它類的實例,被創建的實例通常都具有共同的父類。
Factory Method模式
將對象的創建交由父類中定義的一個標準方法來完成,而不是其構造函數,究竟應該創建何種對象由具體的子類負責決定。
Abstract Factory模式
提供一個共同的接口來創建相互關聯的多個對象。
一、Simple Factory模式:
1、 在這裏,我們先定義水果(Fruit)接口:
public interface Fruit {
void plant(); //水果是被種植的
void enableEat(); //水果能喫
}
2、 蘋果(Apple)是對水果(Fruit)接口的實現:
public class Apple implements Fruit{
public void plant(){
System.out.println("種蘋果!");
}
public void enableEat(){
System.out.println("蘋果好喫!");
}
}
3、 葡萄(Grape)是對水果(Fruit)接口的實現:
public class Grape implements Fruit{
public void plant(){
System.out.println("種葡萄!");
}
public void enableEat(){
System.out.println("葡萄好喫!");
}
}
4、 鴨梨(Pear)是對水果(Fruit)接口的實現:
public class Pear implements Fruit{
public void plant(){
System.out.println("種鴨梨!");
}
public void enableEat(){
System.out.println("鴨梨好喫!");
}
}
5、定義買水果(BuyFruit)這一過程類:
public class BuyFruit {
/**
* 簡單工廠方法
*/
public static Fruit buyFruit(String which){
if (which.equalsIgnoreCase("apple")) { //如果是蘋果,則返回蘋果實例
return new Apple();
}
else if (which.equalsIgnoreCase("pear")){ //如果是鴨梨,則返回鴨梨實例
return new Strawberry();
}
else if (which.equalsIgnoreCase("grape")) { //如果是葡萄,則返回葡萄實例
return new Grape();
}
else{
return null;
}
}
}
6、 編寫測試類:
public class FruitTest {
public static void main(String args[]){
BuyFruit buy = new BuyFruit(); //開始買水果這個過程
buy.buyFruit("apple").enableEat(); //調用蘋果的enableEat()方法
}
}
7、 說明:
A:我要購買蘋果,只需向工廠角色(BuyFruit)請求即可。而工廠角色在接到請求後,會自行判斷創建和提供哪一個產品。
B:但是對於工廠角色(BuyFruit)來說,增加新的產品(比如說增加草莓)就是一個痛苦的過程。工廠角色必須知道每一種產品,如何創建它們,以及何時向客戶端提供它們。換言之,接納新的產品意味着修改這個工廠。
C:因此Simple Factory模式的開放性比較差。
有什麼辦法可以解決這個問題嗎?那就需要Factory Method模式來爲我們服務了。
二、Factory Method模式:
1、同樣,我們先定義水果(Fruit)接口:
public interface Fruit {
void plant(); //水果是被種植的
void enableEat(); //水果能喫
}
2、蘋果(Apple)是對水果(Fruit)接口的實現:
public class Apple implements Fruit{
public void plant(){
System.out.println("種蘋果!");
}
public void enableEat(){
System.out.println("蘋果好喫!");
}
}
3、葡萄(Grape)是對水果(Fruit)接口的實現:
public class Grape implements Fruit{
public void plant(){
System.out.println("種葡萄!");
}
public void enableEat(){
System.out.println("葡萄好喫!");
}
}
4、鴨梨(Pear)是對水果(Fruit)接口的實現:
public class Pear implements Fruit{
public void plant(){
System.out.println("種鴨梨!");
}
public void enableEat(){
System.out.println("鴨梨好喫!");
}
}
5、在這裏我們將買水果(BuyFruit)定義爲接口類:
public interface BuyFruit{
/**
* 工廠方法
*/
public Fruit buyFruit(); //定義買水果這一過程
}
6、買蘋果是(BuyApple)對買水果(BuyFruit)這個接口的實現
public class BuyApple implements BuyFruit{
public Fruit buyFruit(){
return new Apple(); //返回蘋果實例
}
}
7、買鴨梨是(BuyPear)對買水果(BuyFruit)這個接口的實現
public class BuyPear implements BuyFruit{
public Fruit BuyPear (){
return new Pear(); //返回鴨梨實例
}
}
8、買葡萄是(BuyGrape)對買水果(BuyFruit)這個接口的實現
public class BuyGrape implements BuyFruit{
public Fruit BuyGrape (){
return new Grape (); //返回葡萄實例
}
}
9、編寫測試類:
public class FruitTest {
public static void main(String args[]){
BuyApple buy = new BuyApple(); //開始買水果這個過程
buy.buyFruit().enableEat(); //調用蘋果的enableEat()方法
}
}
10、說明:
A:工廠方法模式和簡單工廠模式在結構上的不同是很明顯的。工廠方法模式的核心是一個抽象工廠類,而簡單工廠模式把核心放在一個具體類上。工廠方法模式可以允許很多具體工廠類從抽象工廠類中將創建行爲繼承下來,從而可以成爲多個簡單工廠模式的綜合,進而推廣了簡單工廠模式。
B:工廠方法模式退化後可以變得很像簡單工廠模式。設想如果非常確定一個系統只需要一個具體工廠類,那麼就不妨把抽象工廠類合併到具體的工廠類中去。由於反正只有一個具體工廠類,所以不妨將工廠方法改成爲靜態方法,這時候就得到了簡單工廠模式。C:如果需要加入一個新的水果,那麼只需要加入一個新的水果類以及它所對應的工廠類。沒有必要修改客戶端,也沒有必要修改抽象工廠角色或者其他已有的具體工廠角色。對於增加新的水果類而言,這個系統完全支持“開-閉”原則。
D:對Factory Method模式而言,它只是針對一種類別(如本例中的水果類Fruit),但如果我們還想買肉,那就不行了,這是就必須要Abstract Factory Method模式幫忙了。
三、Abstract Factory模式
1、同樣,我們先定義水果(Fruit)接口:
public interface Fruit {
void plant(); //水果是被種植的
void enableEat(); //水果能喫
}
2、蘋果(Apple)是對水果(Fruit)接口的實現:
public class Apple implements Fruit{
public void plant(){
System.out.println("種蘋果!");
}
public void enableEat(){
System.out.println("蘋果好喫!");
}
}
3、葡萄(Grape)是對水果(Fruit)接口的實現:
public class Grape implements Fruit{
public void plant(){
System.out.println("種葡萄!");
}
public void enableEat(){
System.out.println("葡萄好喫!");
}
}
4、鴨梨(Pear)是對水果(Fruit)接口的實現:
public class Pear implements Fruit{
public void plant(){
System.out.println("種鴨梨!");
}
public void enableEat(){
System.out.println("鴨梨好喫!");
}
}
5、 定義肉(Meat)接口:
public interface Meat {
void feed(); //肉是餵養的
void enableEat(); //肉能喫
}
6、 豬肉(BigMeat)是對肉(Meat)接口的實現:
public class BigMeat implements Meat{
public void feed(){
System.out.println("養豬!");
}
public void enableEat(){
System.out.println("豬肉好喫!");
}
}
7、 牛肉(CowMeat)是對肉(Meat)接口的實現:
public class CowMeat implements Meat {
public void feed(){
System.out.println("養牛!");
}
public void enableEat(){
System.out.println("牛肉好喫!");
}
}
8、 我們可以定義買貨人(Buyer)接口:
public interface Buyer {
/**
* 買水果工廠方法
*/
public Fruit buyFruit(Fruit whichFruit);
/**
* 買肉的工廠方法
*/
public Meat buyMeat(Meat whichMeat);
}
9、 我(MyBuyer)是對買貨人(Buyer)接口的實現:
public class MyBuyer implements Buyer{
/**
* 買水果工廠方法
*/
public Fruit buyFruit(Fruit whichFruit){
return whichFruit;
}
/**
* 買肉的工廠方法
*/
public Meat buyMeat(Meat whichMeat){
return whichMeat;
}
}
10、編寫測試類:
public class MyBuyerAbstractTest {
public static void main(String args[]){
Fruit apple = new Apple(); //蘋果實例
Meat big = new BigMeat(); //豬肉實例
MyBuyer my = new MyBuyer(); //我是買者的實例
my.buyFruit(apple).enableEat(); //我買蘋果
my.buyMeat(big).enableEat(); //我買豬肉
}
}
11、說明:
A:抽象工廠模式可以向客戶端提供一個接口,使得客戶端在不必指定產品的具體類型的情況下,創建多個產品族中的產品對象。這就是抽象工廠模式的用意。
B:抽象工廠模式是所有形態的工廠模式中最爲抽象和最具一般性的一種形態。
C:抽象工廠模式與工廠方法模式的最大區別就在於,工廠方法模式針對的是一個產品(Fruit)等級結構;而抽象工廠模式則需要面對多個產品等級結構(Fruit、Meat)。