菜鳥成長系列-概述
菜鳥成長系列-面向對象的四大基礎特性
菜鳥成長系列-多態、接口和抽象類
菜鳥成長系列-面向對象的6種設計原則
菜鳥成長系列-單例模式java
上一篇咱們已經對建立型模式中的單例模式進行了學習,今天來學習另一個比較重要而且常用的模式-工廠模式;工廠模式專門負責將大量有共同接口的類實例化。其能夠動態的決定將哪個類實例化,沒必要事先知道每次要實例化哪個類。
bash
工廠模式具備如下三種形態:架構
本篇文章將對這三種形態的工廠模式進行一些基本的學習,並經過例子來直觀的感覺下不一樣形態的具體實現方式。最後再分析下JAVA以及Spring中是如何使用的。app
package com.glmapper.design.factory;
/**
* 抽象類角色:food接口,約束類型
* @author glmapper
* @date 2017年12月24日上午10:38:36
*
*/
public interface IFood {
/**
* 提供一個展現食物細節的方法
* @param foodName 食物名稱
*/
public void showFood();
}
複製代碼
package com.glmapper.design.factory;
/**
* 具體產品-食物魚
* @author glmapper
* @date 2017年12月24日上午10:51:29
*
*/
public class FishFood implements IFood
{
@Override
public void showFood() {
System.out.println("一盤魚");
}
}
複製代碼
package com.glmapper.design.factory;
/**
*
* 具體食物:土豆絲
* @author glmapper
* @date 2017年12月24日上午10:47:17
*
*/
public class ShreddedPotatoesFood implements IFood{
@Override
public void showFood() {
System.out.println("一盤土豆絲");
}
}
複製代碼
package com.glmapper.design.factory;
/**
* 工廠角色-食物工廠
*
* @author glmapper
* @date 2017年12月24日上午10:41:10
*
*/
public class SimpleFoodFactory {
/**
* 提供一個靜態方法,用於獲取食物
* @param foodType 食物類型
* @return 具體食物
*/
public static IFood getFood(String foodType){
IFood food = null;
if (foodType.equals("fish")) {
food = new FishFood();
}
if (foodType.equals("potatoes")) {
food = new ShreddedPotatoesFood();
}
return food;
}
}
複製代碼
package com.glmapper.design.factory;
/**
* 客戶端
* @author glmapper
* @date 2017年12月24日上午10:45:17
*
*/
public class MainTest {
public static void main(String[] args) {
IFood fishfood = SimpleFoodFactory.getFood("fish");
fishfood.showFood();
IFood potatoesfood = SimpleFoodFactory.getFood("potatoes");
potatoesfood.showFood();
}
}
複製代碼
一盤魚
一盤土豆絲
複製代碼
OK,菜作完了,能夠吃了。。。ide
咱們來討論下簡單工廠模式的優缺點:工具
優勢:模式的核心是工廠類,這個類含有必要的判斷邏輯,能夠決定在何時建立哪個產品類的實例。而客戶端則能夠免除直接建立產品對象的責任,而僅僅負責消費產品便可。用一句話來講就是:簡單工廠模式這個作法實現了對責任的分割。
缺點:集中了全部產品的建立邏輯,造成了一個無所不能的全職類,可是以前咱們在討論設計原則的時候說過,咱們要儘可能避免這種狀況的發生,這種就很明顯破壞了單一職責這條原則,另外也不知足開閉原則的約束。當咱們須要進行品類擴展時,咱們須要不斷的去修改咱們的工廠的業務邏輯,一方面是工廠類會急速的膨脹,另外一方面由於囊括了不一樣的產品對於咱們後期的維護形成必定的影響。
源碼分析
這個時候一個同事說他是南方人,另一個同事說他是北方人,吃不慣今天的菜。post
好吧,既然這樣,那我就只能點外賣了。。。可是爲了防止他們變卦本身的家鄉,我須要作一個計劃,下面就是計劃圖:從上圖中咱們能夠看出,工廠方法模式的角色包括如下幾種:學習
由於個人同事都是來自不一樣地方的,他們的口味也都不同,可是呢同事都是第一次來我家吃飯,因此爲了招待周全,根據同事不一樣的口味叫不一樣口味的魚。ui
package com.glmapper.design.factory;
/**
*
* 角色1:抽象工廠 - 負責獲取食物
* @author glmapper
* @date 2017年12月24日下午1:59:28
*/
public interface MethodFoodFactory {
//獲取食物的方法
public IFishFood getFood();
}
複製代碼
package com.glmapper.design.factory;
/**
* 南方口味外賣 - 魚
* @author glmapper
* @date 2017年12月24日下午2:03:36
*/
public class SouthFishFactory implements MethodFoodFactory{
@Override
public IFishFood getFood() {
return new SouthFishFood();
}
}
複製代碼
package com.glmapper.design.factory;
/**
* 北方口味外賣 - 魚
* @author glmapper
* @date 2017年12月24日下午2:03:36
*/
public class NorthFishFactory implements MethodFoodFactory{
@Override
public IFishFood getFood() {
// TODO Auto-generated method stub
return new NorthFishFood();
}
}
複製代碼
package com.glmapper.design.factory;
/**
* 南方口味-魚
* @author glmapper
* @date 2017年12月24日下午2:16:17
*/
public class SouthFishFood implements IFishFood{
@Override
public void showFood() {
System.out.println("來自南方廚師作的魚");
}
}
複製代碼
package com.glmapper.design.factory;
/**
* 北方口味 - 魚
* @author glmapper
* @date 2017年12月24日下午2:12:55
*/
public class NorthFishFood implements IFishFood {
@Override
public void showFood() {
System.out.println("來自北方廚師作的魚");
}
}
複製代碼
package com.glmapper.design.factory;
/**
* 客戶端
* @author glmapper
* @date 2017年12月24日上午10:45:17
*/
public class MainTest {
public static void main(String[] args) {
//點一個南方口味外賣
MethodFoodFactory southFoodFactory = new SouthFishFactory();
//點一個北方口味外賣
MethodFoodFactory northFoodFactory = new NorthFishFactory();
//拿到南方口味外賣魚
southFoodFactory.getFood().showFood();
//拿到北方口味外賣魚
northFoodFactory.getFood().showFood();
}
}
複製代碼
來自南方廚師作的魚
來自北方廚師作的魚
複製代碼
OK,這樣咱們就知足了不一樣區域同時關於魚口味的需求了,之後升值加薪就期望他們了。。。
關於工廠方法模式的優缺點:
優勢:
一、 在工廠方法中,用戶只須要知道所要產品的具體工廠,無須關係具體的建立過程,甚至不須要具體產品類的類名。
二、 在系統增長新的產品時,咱們只須要添加一個具體產品類和對應的實現工廠,無需對原工廠進行任何修改,很好地符合了「開閉原則」
缺點:
每次增長一個產品時,都須要增長一個具體類和對象實現工廠,是的系統中類的個數成倍增長,在必定程度上增長了系統的複雜度,同時也增長了系統具體類的依賴。這並非什麼好事。
準備吃飯的時候忽然又來了幾位同事,並且他們有的喜歡吃酸菜魚,有的喜歡吃紅燒魚,這就很頭疼。因而,只能根據他們的須要繼續點外賣。(這個就給出一個結構圖,而且將每種角色都用具體的場景來講明瞭,具體的代碼能夠參考這個圖例本身嘗試一下。)
OK,終於能夠吃飯了!java.text.DateFormat (一個抽象類)這個類相信不少小夥伴都用到過,在java API中,這個類算是一個簡單工廠模式的典型應用了(此處仍是與上篇同樣,不考慮期源碼細節,也不介紹基本用法)。來看它的幾個方法:
做爲一個抽象類,卻提供了不少的靜態工廠方法,就像上面列舉的那三個同樣。有小夥伴可能會疑惑,爲啥子一個抽象類闊以有本身的實例,並經過幾個方法提供本身的實例。咱們知道,抽象類是不能夠有本身的實例對象的,可是須要注意的是,DateFormat的工廠方法是靜態的,並非普通的方法,也就是說,不須要經過建立實例對象的方式去調用。
public final static DateFormat getDateInstance()
{
return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT));
}
複製代碼
getDateInstance方法並無經過調用DateFormat的構造方法來建立對象。
java.net.URL類,類圖以下,
URL對象經過一個工廠方法openConnection()返回一個URLConnection類型的對象。URLConnection是一個抽象類,所以所返還的不多是這個抽象類的實例,而必然是其具體子類的實例。根據java與模式一書的介紹,在java中使用抽象工廠模式的是 JAVA awt的peer架構,經過抽象工廠模式來構建分屬於不一樣操做系統的peer構件。這個我也沒用過,瞭解便可。
關於Spring中工廠模式的使用會在後續Spring源碼分析系列中給你們詳細分析,這裏就不重複了。
今天的學習就到此結束了,祝你們週末愉快。話說今天平安夜,你們都是在家寫代碼嗎?
若是您對系列文章有任何意見,能夠給我留言,感謝你們。
下面是一個接蘋果的姿式,呼呼呼.....