工厂模式,从第三方登陆提及

如今的不少平台在登录的时候,下面都会有一排选项,能够选择微信、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等开源框架中应用了大量的设计模式,工厂模式天然少不了,无论学习哪一种设计模式,咱们均可以去参考这些开源框架,它可以加深你对设计模式的理解。

源代码

文章不足之处,望你们多多指点,共同窗习,共同进步

最后

打个小广告,欢迎扫码关注微信公众号:「平头哥的技术博文」,一块儿进步吧。

平头哥的技术博文
相关文章
相关标签/搜索