一、概述
1.1使用場景。
在任何需要生成複雜對象的地方,都可以使用工廠方法模式, 直接用new可以完成的不需要用工廠模式。個人了解,重點就是這個複雜 (構造函數有很多參數)和是否可以直接用new。
二、工廠模式的五種寫法
2.1簡單的靜态工廠模式。
/**
* 圖形抽象類
*/
public abstract class Shap {
/**
* 描述形狀(畫畫)
*/
public abstract void draw();
}
/**
* 圓形類
*/
public class Circle extends Shap {
public void draw() {
System.out.println("這是圓形...");
}
}
/**
* 長方形類
*/
public class Rectangle extends Shap {
public void draw() {
System.out.println("這是長方形...");
}
}
/**
* 正方形類
*/
public class Square extends Shap {
public void draw() {
System.out.println("這是正方形...");
}
}
/**
* 簡單靜态工廠類
*/
public class SimpleStaticShapFactory {
// 長方形
public static final int TYPE_RECTANGLE = ;
// 正方形
public static final int TYPE_SQUARE = ;
// 圓形
public static final int TYPE_CIRCLE = ;
public static Shap createShap(int type) {
switch (type) {
case TYPE_RECTANGLE:
return new Rectangle();
case TYPE_SQUARE:
return new Square();
case TYPE_CIRCLE:
default:
return new Circle();
}
}
}
/**
* 測試類
*/
public class Test {
public static void main(String[] args) {
// 建立執行個體
Shap shap = SimpleStaticShapFactory.createShap(SimpleStaticShapFactory.TYPE_CIRCLE);
shap.draw();
// 建立執行個體
Shap shap2 = SimpleStaticShapFactory.createShap(SimpleStaticShapFactory.TYPE_SQUARE);
shap2.draw();
}
}
// 運作結果
這是圓形...
這是正方形...
特點:
(1)它是一個具體的類,非接口抽象類。有一個重要的createShap()方法,利用if或者 switch建立産品并傳回。
(2)createShap()方法通常是靜态的,是以也稱之為靜态工廠。
缺點:
(1)擴充性差(我想增加一種圖形,除了新增一個圖形類,還需要修改工廠類方法)。
(2)不同的圖形類需要不同額外參數的時候不支援。
2.2基于反射的簡單工廠模式。
/**
* 工廠類
*/
public class ReflectFactory {
/**
* @param clzzz Class對象
* @return 執行個體對象
*/
public static <T extends Shap> T createShap(Class<T> clzz) {
T instance = null;
try {
instance = (T) Class.forName(clzz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
}
/**
* 測試類
*/
public class Test {
public static void main(String[] args) {
//建立執行個體
Shap shap = ReflectFactory.createShap(Rectangle.class);
shap.draw();
//建立執行個體
Shap shap2 = ReflectFactory.createShap(Square.class);
shap2.draw();
}
}
// 運作結果
這是長方形...
這是正方形...
特點:
(1)它也是一個具體的類,非接口抽象類。但它的createShap()方法,是利用反射機制生成對象傳回,好處是增加一種産品時,不需要修改createShap()的代碼。
缺點:
(1)這種寫法粗看牛逼,細想之下,不談reflection的效率還有以下問題。
(2)個人覺得不好,因為Class.forName(clzz.getName()).newInstance()調用的是無參構造函數生成對象,它和new Object()是一樣的性質,而工廠方法應該用于複雜對象的初始化 ,當需要調用有參的構造函數時便無能為力了,這樣像為了工廠而工廠。
(3)不同的産品需要不同額外參數的時候 不支援。
2.3多方法靜态工廠模式(常用)。
/**
* 工廠類
*/
public class MultipartStaticFactory {
/**
* 建立圓形
* @return Circle
*/
public static Shap createCircle() {
return new Circle();
}
/**
* 建立長方形
* @return Rectangle
*/
public static Shap createRectangle() {
return new Rectangle();
}
/**
* 建立正方形
* @return Square
*/
public static Shap createSquare() {
return new Square();
}
}
/**
* 測試類
*/
public class Test {
public static void main(String[] args) {
// 建立執行個體
Shap shap = MultipartStaticFactory.createCircle();
shap.draw();
// 建立執行個體
Shap shap2 = MultipartStaticFactory.createSquare();
shap2.draw();
}
}
//運作結果
這是圓形...
這是正方形...
特點:
(1)使用前面兩張方法實作的工廠,都有一個缺點:不同的類需要不同額外參數的時候不支援。
(2) 如果使用時傳遞的type、Class出錯,将不能得到正确的對象,容錯率不高。 而多方法的工廠模式為不同産品,提供不同的生産方法,使用時需要哪種産品就調用該種産品的方法,使用友善、容錯率高。
(3)這個例子可以感受到工廠方法的魅力了吧:友善建立同種類型的複雜參數對象。
此種設計模式還在Executors源碼用到:
Executor是生成各種線程池的工廠,其采用的便是多方法靜态工廠模式。
/**
* java.util.concurrent.Executors類部分源碼
*/
public class Executors {
/**
* ThreadPoolExecutor方法有5個參數,有部分參數寫法固定,而工廠類就隻需要傳入一個參數
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
/**
* 假如JDK想增加建立ForkJoinPool類的方法,隻想配置parallelism參數,便在類裡增加一個如下的方法
*/
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
public static ExecutorService newWorkStealingPool() {
return new ForkJoinPool
(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
2.4普通工廠模式。
/**
* 抽象工廠類,生産圖形
*/
public abstract class ShapFactory {
abstract Shap createShap();
}
/**
* 具體工廠子類,圓形工廠
*/
public class CircleFactory extends ShapFactory {
@Override
Shap createShap() {
return new Circle();
}
}
/**
* 具體工廠子類,長方形工廠
*/
public class RectangleFactory extends ShapFactory {
@Override
Shap createShap() {
return new Rectangle();
}
}
/**
* 具體工廠子類,正方形工廠
*/
public class SquareFactory extends ShapFactory {
@Override
Shap createShap() {
return new Square();
}
}
/**
* 測試類
*/
public class Test {
public static void main(String[] args) {
// 建立圓形工廠
ShapFactory shapFactory = new CircleFactory();
// 建立圓形執行個體
Shap circle = shapFactory.createShap();
circle.draw();
// 建立正方形工廠
ShapFactory shapFactory2 = new SquareFactory();
// 建立正方形執行個體
Shap Square = shapFactory2.createShap();
Square.draw();
}
}
// 運作結果
這是圓形...
這是正方形...
特點:
(1)普通工廠就是把簡單工廠【2.1簡單的靜态工廠模式】中具體的工廠類,劃分成兩層:抽象工廠層和具體的工廠子類層。
(2)可以看出,普通工廠模式特點:不僅僅做出來的産品要抽象, 工廠也應該需要抽象。
(3)工廠方法使一個産品類的執行個體化延遲到其具體工廠子類。
(4)工廠方法的好處就是更擁抱變化。當需求變化,隻需要增删相應的類,不需要修改
(5)而簡單工廠【2.1簡單的靜态工廠模式】需要修改工廠類的createShap()方法和具體圖形類,多方法靜态工廠【2.3多方法靜态工廠模式】模式需要增加一個靜态方法和具體圖形類。
缺點:
(1) 引入抽象工廠層後,每次新增一個具體圖形類,也要同時新增一個具體工廠類。
2.4抽象工廠模式。
/**
* 飲料抽象類
*/
public abstract class Drink {
/**
* 描述每種飲料多少錢
*/
public abstract void prices();
}
/**
* 可樂類
*/
public class Cola extends Drink {
@Override
public void prices() {
System.out.println("可口可樂3.0元...");
}
}
/**
* 牛奶類
*/
public class Milk extends Drink {
@Override
public void prices() {
System.out.println("牛奶2.5元...");
}
}
/**
* 抽象工廠類
*/
public abstract class DrinkAndDraw {
/**
* 喝飲料
*
* @return
*/
public abstract Drink doDrink();
/**
* 畫畫
*
* @return
*/
public abstract Shap doDraw();
}
/**
* 具體工廠類1
*/
public class FactoryOne extends DrinkAndDraw {
/**
* 喝可樂
*/
@Override
public Drink doDrink() {
return new Cola();
}
/**
* 畫圓形
*/
@Override
public Shap doDraw() {
return new Circle();
}
}
/**
* 具體工廠類2
*/
public class FactoryTwo extends DrinkAndDraw {
/**
* 喝牛奶
*/
@Override
public Drink doDrink() {
return new Milk();
}
/**
* 畫正方形
*/
@Override
public Shap doDraw() {
return new Square();
}
}
/**
* 測試類
*/
public class Test {
public static void main(String[] args) {
// 上幼稚園的小明一邊喝可口可樂,一邊在畫圓形
// 建立工廠1的執行個體,傳回的方法是可樂執行個體的方法和圓形執行個體的方法
DrinkAndDraw drinkAndDraw = new FactoryOne();
// 調用可樂執行個體的喝可樂方法
drinkAndDraw.doDrink().prices();
// 調用圓形執行個體的畫圓形方法
drinkAndDraw.doDraw().draw();
// 上幼稚園的小明一邊喝牛奶,一邊在畫正方形
DrinkAndDraw drinkAndDraw2 = new FactoryTwo();
drinkAndDraw2.doDrink().prices();
drinkAndDraw2.doDraw().draw();
}
}
// 運作結果
可口可樂元...
這是圓形...
牛奶元...
這是正方形...
特點:
(1)将工廠也抽象了,在使用時,工廠和産品都是面向接口程式設計。
缺點:
(1)如果每次擴充新抽象類,比如讀書抽象類,那就需要新加具體實作類如讀小說還是讀教科書,然後需要修改抽象工廠類,而後所有的具體工廠子類,都被牽連,需要同步被修改。