java 設計模式--工廠模式

工廠模式在《Java與模式》中分爲三類:
1)簡單工廠模式(Simple Factory):不利於產生系列產品;
2)工廠方法模式(Factory Method):又稱爲多形性工廠;
3)抽象工廠模式(Abstract Factory):又稱爲工具箱,產生產品族,但不利於產生新的產品;
java

           這三種模式從上到下逐步抽象,而且更具通常性。
            GOF在《設計模式》一書中將工廠模式分爲兩類:工廠方法模式(Factory Method)與抽象工廠模式(Abstract Factory)。將簡單工廠模式(Simple Factory)看爲工廠方法模式的一種特例,二者歸爲一類。設計模式

現單個的講,最後再講這三個的區別
這篇文章主要經過一個農場的實例來說解,這也是java與模式書中的例
子,只不過我對一些部分進行了簡化,一些部分進行了擴充,以幫助理解例
子以下:
有一個農場公司,專門向市場銷售各種水果有以下水果:
葡萄(grape)app

草莓(Strawberry)
蘋果(apple)

簡單工廠模式:
less

簡單工廠模式又稱靜態工廠方法模式。重命名上就能夠看出這個模式必定很簡單。它存在的目的很簡單:定義一個用於建立對象的接口。
在簡單工廠模式中,一個工廠類處於對產品類實例化調用的中心位置上,它決定那一個產品類應當被實例化, 如同一個交通警察站在來往的車輛流中,決定放行那一個方向的車輛向那一個方向流動同樣。函數

     先來看看它的組成:
        1) 工廠類角色:這是本模式的核心,含有必定的商業邏輯和判斷邏輯。在java中它每每由一個具體類實現。
        2) 抽象產品角色:它通常是具體產品繼承的父類或者實現的接口。在java中由接口或者抽象類來實現。
        3) 具體產品角色:工廠類所建立的對象就是此角色的實例。在java中由一個具體類實現。工具


這個比較簡單,寫一下源代碼源代碼中給出了必須的註釋代碼比書上的要
簡單一些,排版也好看一些,只是爲了讓新手更好的理解
ui

Fruit.java:
public interface Fruit
{
/**
* 水果與其它植物相比有一些專門的屬性,以便與農場的
* 其它植物區分開這裏的水果假設它必須具有的方法:
* 生長grow()收穫harvest()種植plant()
*/
void grow();
void harvest();
void plant();
}

下面是Apple類的函數Apple.java:
this

public class Apple implements Fruit
{
/** 
* 蘋果是水果類的一種,所以它必須實現水果接口的全部方法即
* grow()harvest()plant()三個函數另外,因爲蘋果是多年生植物,
* 因此多出一個treeAge性質,描述蘋果的樹齡
*/
private int treeAge;
public void grow() { //蘋果的生長函數代碼 }
public void harvest() { //蘋果的收穫函數代碼 }
public void plant() { //蘋果的種植函數代碼 }
public int getTreeAge() { return treeAge; }
public void setTreeAge(int treeAge) { this.treeAge = treeAge; }
}

下面是Grape類的函數Grape.java:
設計

public class Grape implements Fruit
{
/** 
* 葡萄是水果類的一種,所以它必須實現水果接口的全部方法即
* grow()harvest()plant()三個函數另外,因爲葡萄分爲有籽和無籽
* 兩種,所以多出一個seedless性質,描述葡萄有籽仍是無籽
*/
private boolean seedless;
public void grow() { //葡萄的生長函數代碼 }
public void harvest() { //葡萄的收穫函數代碼 }
public void plant() { //葡萄的種植函數代碼 }
public boolean getSeedless() { return seedless; }
public void setSeedless(boolean seedless) { this.seedless = seedless; }
}

下面是Strawberry類的函數Strawberry.java:
code

public class Strawberry implements Fruit
{
/** 
* 草莓是水果類的一種,所以它必須實現水果接口的全部方法即
* grow()harvest()plant()三個函數另外,這裏假設草莓分爲大棚草莓和通常
* 草莓(即沒有棚的草莓)所以草莓比通常水果多出一個性質coteless,描述草莓
* 是大棚草莓仍是沒有大棚的草莓
*/
private boolean coteless;
public void grow() { //草莓的生長函數代碼 }
public void harvest() { //草莓的收穫函數代碼 }
public void plant() { //草莓的種植函數代碼 }
public boolean getCoteless() { return coteless; }
public void setCoteless(boolean coteless) { this. coteless = coteless; }
}

農場的園丁也是系統的一部分,天然要有一個合適的類來表明,咱們用FruitGardener類
來表示FruitGardener類會根據客戶端的要求,建立出不一樣的水果對象,好比蘋果(apple),
葡萄(grape)或草莓(strawberry)的實例代碼以下所示:
FruitGardener.java:

public class FruitGardener
{
/**
* 經過下面的表態工廠方法,能夠根據客戶的須要,建立出不一樣的水果對象
* 若是提供的參數是apple則經過return new Apple()建立出蘋果實例
* 若是是提供的參數是grape則建立葡萄實例,這正是簡單工廠方法之精髓
*/
public static Fruit factory(String which) throws BadFruitException
{
if (which.equalsIgnoreCase("apple")) { return new Apple(); }
else if (which.equalsIgnoreCase("strawberry")) { return new Strawberry(); }
else if (which.equalsIgnoreCase("grape")) { return new Grape(); }
else { throw new BadFruitException("Bad fruit request"); }
}
}

簡單工廠方法的優勢是當在系統中引入新產品時沒必要修改客戶端,但須要個修改工廠
類,將必要的邏輯加入到工廠類中工廠方法模式就克服了以上缺點,下面談談工廠
方法模式

工廠方法模式:

clip_image006

工廠方法模式是簡單工廠模式的進一步抽象化和推廣,工廠方法模式裏再也不只由一個工廠類決定那一個產品類應當被實例化,這個決定被交給抽象工廠的子類去作。
  來看下它的組成:

     1)抽象工廠角色: 這是工廠方法模式的核心,它與應用程序無關。是具體工廠角色必須實現的接口或者必須繼承的父類。在java中它由抽象類或者接口來實現。
      2)具體工廠角色:它含有和具體業務邏輯有關的代碼。由應用程序調用以建立對應的具體產品的對象。
      3)抽象產品角色:它是具體產品繼承的父類或者是實現的接口。在java中通常有抽象類或者接口來實現。
      4)具體產品角色:具體工廠角色所建立的對象就是此角色的實例。在java中由具體的類來實現。


因爲水果接口以及grape類strawberry類apple類的代碼都和上面的同樣,因此下
面相關的源碼去掉了註釋
Fruit.java:

public interface Fruit
{
void grow();
void harvest();
void plant();
}

Apple.java:

public class Apple implements Fruit
{
private int treeAge;
public void grow() { //蘋果的生長函數代碼 }
public void harvest() { //蘋果的收穫函數代碼 }
public void plant() { //蘋果的種植函數代碼 }
public int getTreeAge() { return treeAge; }
public void setTreeAge(int treeAge) { this.treeAge = treeAge; }
}

Grape.java:

public class Grape implements Fruit
{
private boolean seedless;
public void grow() { //葡萄的生長函數代碼 }
public void harvest() { //葡萄的收穫函數代碼 }
public void plant() { //葡萄的種植函數代碼 }
public boolean getSeedless() { return seedless; }
public void setSeedless(boolean seedless) { this.seedless = seedless; }
}

Strawberry.java:

public class Strawberry implements Fruit
{
private boolean coteless;
public void grow() { //草莓的生長函數代碼 }
public void harvest() { //草莓的收穫函數代碼 }
public void plant() { //草莓的種植函數代碼 }
public boolean getCoteless() { return coteless; }
public void setCoteless(boolean coteless) { this. coteless = coteless; }
}

下面的源碼就是工廠方法模式的重點了,在簡單工廠模式中,將這裏將FruitGardener定
義爲一個類,即園丁要管理園裏的全部水果,若是園丁哪天病了,水果都不能管理了
在工廠方法模式中將FruitGardener定義爲一個接口,而將管理水果的角色劃分得更細,
好比有
葡萄園丁草莓園丁蘋果園丁等等具體角色實現FruitGardener接口的工廠
方法源碼以下所示:
接口FruitGardener的源碼:

public interface FruitGardener
{
Fruit factory();
}

蘋果園丁類AppleGardener.java的源碼:

public class AppleGardener implements FruitGardener
{
public Fruit factory() { return new Apple(); }
}

葡萄園丁類GrapeGardener.java的源碼:

public class GrapeGardener implements FruitGardener
{
public Fruit factory() { return new Grape(); }
}

草莓園丁類StrawberryGardener.java的源碼:

public class StrawberryGardener implements FruitGardener
{
public Fruit factory() { return new Strawberry(); }
}

由以上源碼能夠看出,使用工廠方法模式保持了簡單工廠模式的優勢,克服了其缺點
當在系統中引入新產品時,既沒必要修改客戶端,又沒必要修改具體工廠角色能夠較好
的對系統進行擴展

抽象工廠模式:

clip_image008


如今工廠再次大發展,要引進塑料大棚技術,在大棚裏種植熱帶(Tropical)和亞熱帶的
水果和蔬菜(Veggie)其中水果分爲TropicalFruit和NorthernFruit,蔬菜分爲TropicalVeggie
和NorthernVeggie園丁包括TropicalGardener和NorthernGardener也就是說,
TropicalGardener專門管理TropicalFruit和TropicalGardener,NorthernGardener專門
管理NorthernFruit和NorthernVeggie抽象工廠模式在這個例子中的源碼以下所示:
Fruit.java:

public interface Fruit { }

NorthernFruit.java:

public class NorthernFruit implements Fruit
{
private String name;
public NorthernFruit(String name) { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}

TropicalFruit.java:

public class TropicalFruit implements Fruit
{
private String name;
public TropicalFruit(String name) { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}

Veggie.java:

public interface Veggie { }
TropicalVeggie.java:
public class TropicalVeggie implements Veggie
{
private String name;
public TropicalVeggie(String name) { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}

NorthernVeggie.java:

public class NorthernVeggie implements Veggie
{
private String name;
public NorthernVeggie(String name) { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}

Gardener.java:

public interface Gardener
{
Fruit createFruit(String name);
Veggie createVeggie(String name);
}

TropicalGardener.java:

public class TropicalGardener implements Gardener
{
public Fruit createFruit(String name) { return new TropicalFruit(name); }
public Veggie createVeggie(String name) { return new TropicalVeggie(name); }
}

NorthernGardener.java:

public class NorthernGardener implements Gardener
{
public Fruit createFruit(String name) { return new NorthernFruit(name); }
public Veggie createVeggie(String name) { return new NorthernVeggie(name); }
}

爲了簡單起見,這裏只講一下增長新產品(族)時該系統如何擴展(關於產品族相關
知識,請看此書的相關章節,不過不懂產品族也沒有關係,這裏寫得很簡單,確定能
看懂)好比如今要增長南方水果(SouthFruit)和南方蔬菜(SouthVeggie)那
麼只要增長以下代碼便可很容易的擴展:
SouthFruit.java:

public class SouthFruit implements Fruit
{
private String name;
public SouthFruit (String name) { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}

SouthVeggie.java:

public class SouthVeggie implements Veggie
{
private String name;
public SouthVeggie (String name) { }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}

SouthGardener.java:

public class SouthGardener implements Gardener
{
public Fruit createFruit(String name) { return new SouthFruit(name); }
public Veggie createVeggie(String name) { return new SouthVeggie(name); }
}
相關文章
相關標籤/搜索