工廠模式,從第三方登陸提及

如今的不少平臺在登錄的時候,下面都會有一排選項,能夠選擇微信、QQ、微博帳號等登錄,這些帳號對平臺來講都是第三方帳號。第三方帳號登錄是最近幾年流行起來的,第三方帳號登陸通常都是基於OAuth2.0協議開發的。若是你不瞭解OAuth2.0協議,能夠自行百度,也許會對你看這篇文章有所幫助。java

如今因爲公司要給平臺引入流量,爲了下降註冊門檻,讓更多的人來使用大家的平臺,領導決定在大家的平臺上接入第三方帳號登錄功能。現階段先接入微信、支付寶、QQ、GitHub 這四個第三方帳號登錄。這個任務也順利的落到你的頭上,因爲你瞭解OAuth2.0協議,你知道這個是一個固定的三段式操做,第一步獲取Authorization Code,第二步獲取Access Token,第三步調用信息接口,可是每一個平臺返回來的數據字段或者格式可能會不同,因此你根據你的開發經驗,爲第三方帳號登陸模塊抽取出來了一個IdentityProvider抽象類,該類主要有上面提到的三步須要的接口,IdentityProvider類的代碼以下:git

public abstract class IdentityProvider {

    // 獲取Authorization Code
    abstract void authorizationCode();

    // 獲取 Access Token
    abstract void accessToken();

    // 獲取用戶信息
    abstract void getUserInfo();
}

複製代碼

每個第三方帳號平臺都繼承IdentityProvider,根據每一個第三方帳號平臺的規則去實現這三個接口,咱們已支付寶爲例,咱們定義一個AliPayIdentityProvider類,該類繼承了IdentityProvider類,AliPayIdentityProvider類代碼以下:程序員

/** * 支付寶 第三方登錄具體實現 */
public class AliPayIdentityProvider extends IdentityProvider{

    private static final String APPID = "你申請的運用id";
    private static final String APPKEY = "你的私鑰";

    public AliPayIdentityProvider() {
        System.out.println("我是支付寶第三方登錄具體實現");
    }

    @Override
    abstract void getUserInfo(){
        // 獲取用戶信息
    }

    @Override
    public void authorizationCode() {
        //獲取authorization Code
    }

    @Override
    public void accessToken() {
        //獲取access Token
    }
}
複製代碼

四個第三方帳號登陸平臺都按照上面的方式作了具體的實現,除此以外,你還建立了一個IdentityFactory類,該類是建立實例的惟一入口,裏面提供了一個靜態create方法,create方法的做用是根據傳入的參數返回對應的第三方帳號平臺實例。IdentityFactory類代碼以下:github

public class IdentityFactory {
    /** * 第三方登錄實例獲取 * @param type 標識符,1:支付寶登錄 2:微信登錄 3:QQ登陸 4:github登錄 */
    public static IdentityProvider create(int type){
        IdentityProvider identityProvider = null;
        switch (type){
            case 1:
                identityProvider = new AliPayIdentityProvider();
                break;
            case 2:
                identityProvider = new WeChatIdentityProvider();
                break;
            case 3:
                identityProvider = new QQIdentityProvider();
                break;
            case 4:
                identityProvider = new GitHubIdentityProvider();
                break;
        }
        return identityProvider;
    }
}
複製代碼

客戶端調用時只須要調用create()方法便可以獲取對應的實例,好比要使用GitHub帳號登錄,咱們只要調用IdentityProvider identityProvider = IdentityFactory.create(4);,獲取到GitHubIdentityProvider,獲取到對象以後,能夠進行GitHub帳號登錄的具體操做。提交、部署、測試、上線,完美完成任務。spring

在第三方帳號平臺登錄功能的實現中,你使用到了一種設計模式,叫做簡單工廠模式,此時你內心確定大喊一聲,臥槽,這就用上了設計模式?是的,沒錯,這就是設計模式。既然你好奇,那咱們就一塊兒來看看簡單工廠模式。設計模式

簡單工廠模式的定義

簡單工廠模式(Simple Factory Pattern):又稱爲靜態工廠方法(Static Factory Method)模式,是建立型模式的一種。在簡單工廠模式中,有一個工廠類來負責其餘類的實例建立,這些被建立的實例類都有一個共同的父類,在咱們的第三方帳號登錄中AliPayIdentityProviderWeChatIdentityProvider都是被實例化的類,它們都有一個共同的父類IdentityProvider,在簡單工廠模式中,工廠類中能夠根據傳入的參數返回不一樣的實例,在咱們的IdentityFactory類中,咱們提供了一個靜態的create(int type),能夠根據傳入的類型返回不一樣的實例。因此咱們這個是標準的簡單工廠模式的實例。微信

上面這一大段很差理解?不要緊,那咱們在抽象一下,簡單工廠模式主要有如下三個成員:框架

  • 抽象產品:抽象產品角色是所建立的全部對象的父類,負責描述全部實例所共有的公共接口,例如IdentityProvider
  • 具體產品:具體產品角色是建立目標,全部建立的對象都充當這個角色的某個具體類的實例,例如AliPayIdentityProvider
  • 工廠類:負責實現建立全部實例的內部邏輯,例如IdentityFactory

咱們再來看一下簡單工廠模式的UML圖: ide

這些該明白簡單工廠模式了吧,雖然名字中帶有簡單兩個字,可是按照常理來講,就算再簡單,也該會有一些優勢吧。既然你還好奇,那就繼續來簡單工廠模式有哪些優勢吧。學習

簡單工廠模式的優勢

  • 工廠類含有必要的判斷邏輯,能夠決定在何時建立哪個產品類的實例,客戶端能夠免除直接建立產品對象的責任,而僅僅「消費」產品;簡單工廠模式經過這種作法實現了對責任的分割,它提供了專門的工廠類用於建立對象。
  • 客戶端無須知道所建立的具體產品類的類名,只須要知道具體產品類所對應的參數便可,對於一些複雜的類名,經過簡單工廠模式能夠減小使用者的記憶量。
  • 經過引入配置文件,能夠在不修改任何客戶端代碼的狀況下更換和增長新的具體產品類,在必定程度上提升了系統的靈活性。

第三方帳號登錄功能上線後,大家公司平臺的用戶急速加強,boss甚是高興,因而又給你安排活來了,此次boss叫你把微博帳號登錄加上,實現使用微博帳號登錄到大家的平臺,有了前面的經驗以後,這事對你來講太簡單的。你給系統新增了一個WeiBoIdentityProvider類,用來實現微博帳號登陸,WeiBoIdentityProvider類以下:

/** * 微博帳號登錄 */
public class WeiBoIdentityProvider extends IdentityProvider{

    private static final String APPID = "你申請的運用id";
    private static final String APPKEY = "你的私鑰";

    public WeiBoIdentityProvider() {
        System.out.println("我是微博第三方登錄具體實現");
    }

    @Override
    abstract void getUserInfo(){
        // 獲取用戶信息
    }

    @Override
    public void authorizationCode() {
        //
    }

    @Override
    public void accessToken() {

    }
}
複製代碼

IdentityFactory類中添加了case 5分支,用來返回微博帳號登錄實例,變動以後IdentityFactory類以下::

public class IdentityFactory {
    /** * 第三方登錄驗證 * @param type 標識符,1:支付寶登錄 2:微信登錄 3:QQ登陸 4:github登錄 5:微博帳號 */
    public static IdentityProvider crete(int type){
        IdentityProvider identityProvider = null;
        switch (type){
            case 1:
                identityProvider = new AliPayIdentityProvider();
                break;
            case 2:
                identityProvider = new WeChatIdentityProvider();
                break;
            case 3:
                identityProvider = new QQIdentityProvider();
                break;
            case 4:
                identityProvider = new GitHubIdentityProvider();
            case 5:
                identityProvider = new WeiBoIdentityProvider();
                break;
        }
        return identityProvider;
    }
}
複製代碼

部署、測試微博帳號登錄,沒有問題,打包上線,關機下班。上線以後,大量用戶反饋GitHub帳號登錄不上。小夥子,出來接鍋了,因而你又要屁顛屁顛的跑回公司加班改 bug ,苦逼的程序員。你找呀找呀,最後發現了,case 4break語句被你刪掉了,因此在使用GitHub帳號登錄時,IdentityFactory工廠返回的實例一直都是WeiBoIdentityProvider,致使GitHub帳號登錄會失敗。不經意間的一個小失誤,形成了一次線上事故。生產上都出事了,後果你懂的。雖然這事故是你人爲形成的,但這也是簡單工廠模式的缺點,你每新增第三方帳號登入平臺時,都須要去改動工廠類,這不免會出現這種誤刪的狀況。簡單工廠模式雖然簡單,可是也有很多缺點,那咱們一塊兒看看簡單工廠模式有哪些缺點吧。

簡單工廠模式的缺點

  • 違背「開放 - 關閉原則」,一旦添加新產品就不得不修改工廠類的邏輯,這樣就容易形成錯誤,就像咱們上面那樣,一不當心形成線上事故
  • 工廠類集中了全部實例(產品)的建立邏輯,一旦這個工廠不能正常工做,整個系統都會受到影響
  • 簡單工廠模式因爲使用了靜態工廠方法,形成工廠角色沒法造成基於繼承的等級結構。

通過了此次事故以後,你一心想證實本身,從新得到領導的賞識,你下定決心要對第三方帳號登錄模塊進行重構。老話說的好:在哪裏跌倒就要在哪裏爬起來。因而你想呀想呀,最後靈光一現,須要對IdentityFactory類進行重構,工廠類也須要像提供方同樣,提取出一個抽象類,而後每一個提供方有本身的工廠,這樣就能夠避免新增時對原有系統模塊的改動。因而你抽象出來一個IdentityProviderFactory類,用來定義工廠須要的接口。IdentityProviderFactory類以下:

/** * 第三方登錄抽象工廠 */
public abstract class IdentityProviderFactory<T> {
    // 建立具體的IdentityProvider
    public abstract IdentityProvider create();
}
複製代碼

每一個第三方帳號平臺都須要有本身的生產工廠,這個工廠必須繼承IdentityProviderFactory類,而後重寫create()方法,在create()方法裏實例化本身的identityProvider實現類,咱們以支付寶工廠爲例,咱們須要建立一個AliPayIdentityProviderFactory類,AliPayIdentityProviderFactory類代碼以下:

/** * 支付寶第三方登錄工廠類 */
public class AliPayIdentityProviderFactory extends IdentityProviderFactory<AliPayIdentityProvider> {
    @Override
    public IdentityProvider create() {
        //支付寶登陸實現實例
        return new AliPayIdentityProvider();
    }
}
複製代碼

create()方法中返回AliPayIdentityProvider實例,每一個工廠都返回對應的實例就能夠,客戶端在調用時,也要發生相應的改變,不在傳入參數來獲取實例,而是經過調用對應的工廠來獲取實例。好比咱們使用支付寶帳號登錄

// 調用支付寶工廠
IdentityProviderFactory providerFactory  = new AliPayIdentityProviderFactory();
// 獲取IdentityProvider
IdentityProvider provider = providerFactory.create();
// 一些列第三方認證操做
複製代碼

重構以後,咱們確定不會再出現上一次的問題,由於如今每一個第三方帳號提供方都有本身的工廠,每一個產品的構建運行都是獨立的。小夥子,恭喜你,你離升職加薪不遠了。

在你重構的過程當中,你也將簡單工廠模式進行了升級,如今它不叫簡單工廠模式了,由於它已經不簡單了,如今的模式叫做工廠方法模式(Factory Method Pattern)。既然咱們都用上了工廠方法模式,那就不妨一塊兒來了解一下工廠方法模式吧。

工廠方法模式的定義

工廠方法模式(Factory Method Pattern)又稱爲工廠模式,也叫虛擬構造器(Virtual Constructor)模式或者多態工廠(Polymorphic Factory)模式,它也是類建立型模式的一種。工廠方法模式與簡單工廠模式的區別在於,在工廠方法模式中,實例的建立不是集中在一個工廠中,而是抽取出來了一個工廠父類,工廠父類負責定義建立產品對象的公共接口,而工廠子類則負責生成具體的產品對象,這樣作的目的是將產品類的實例化操做延遲到工廠子類中完成,即經過工廠子類來肯定究竟應該實例化哪個具體產品類。就像咱們的IdentityProviderFactory類和AliPayIdentityProviderFactory類。

跟簡單工廠模式同樣,咱們對工廠方法模式也進行抽象一下,工廠方法模式有下面四個成員:

  • 抽象產品:定義好產品具備的屬性方法,例如IdentityProvider
  • 具體產品:具體的產品實現,例如AliPayIdentityProvider
  • 抽象工廠:定義好工廠的抽象方法,例如IdentityProviderFactory
  • 具體工廠:具體的生產工廠,例如AliPayIdentityProviderFactory

老慣例,一塊兒看看工廠方法模式的UML圖,加深印象:

工廠方法模式好處在咱們重構第三方帳號登陸模塊的時候,咱們已經體驗到了,工廠方法模式的好處可不止那麼一點,一塊兒來看看工廠方法模式有哪些優勢?

工廠方法模式的優勢

  • 工廠方法模式的擴展性很是強,在系統中加入新產品時,無須修改抽象工廠和抽象產品提供的接口,而只要添加一個具體工廠和具體產品,就能夠擁抱變化,就像若是咱們如今要接入釘釘帳號登錄,咱們只須要建立DingDingIdentityProviderFactoryDingDingIdentityProvider就行了
  • 良好的封裝性,代碼結構清晰。調用者須要一個具體的產品對象時,只須要知道這個產品的類名就能夠了,不須要知道具體的建立過程,下降的模塊之間的耦合
  • 屏蔽產品類,產品類的實現如何變化,調用者不須要關係,它只關係產品的接口,只要接口保持不變,系統中的上層模塊就不須要變化。因此工廠方法模式常常用來解耦,高層模塊只須要知道產品的抽象類,實現類不須要關係,這符合迪米特法則,也符合依賴倒置原則。

工廠方法模式雖然有諸多好處,可是它也有很多缺點,由於不可能有天衣無縫的設計模式,那咱們一塊兒來看看工廠方法模式的缺點。

工廠方法模式的缺點

  • 增長了系統複雜度,咱們將工廠類拆分出來,無形之中給咱們的系統帶來了複雜性
  • 增長了開發量,在使用簡單工廠模式時,咱們只想要添加一個case分支,如今則須要建立類
  • 因爲考慮到系統的可擴展性,須要引入抽象層,在客戶端代碼中均使用抽象層進行定義,增長了系統的抽象性和理解難度,且在實現時可能須要用到DOM、反射等技術,增長了系統的實現難度

總結

本文主要簡單的介紹了一下簡單工廠模式和工廠方法模式這兩種設計模式,經過第三方帳號登錄這個案例,從簡單工廠模式開始,一步一步的到了工廠方法模式。想要更深刻的瞭解工廠模式,須要參考大量的案例,spring等開源框架中應用了大量的設計模式,工廠模式天然少不了,無論學習哪一種設計模式,咱們均可以去參考這些開源框架,它可以加深你對設計模式的理解。

源代碼

文章不足之處,望你們多多指點,共同窗習,共同進步

最後

打個小廣告,歡迎掃碼關注微信公衆號:「平頭哥的技術博文」,一塊兒進步吧。

平頭哥的技術博文
相關文章
相關標籤/搜索