Android中工厂模式

设计模式系列:
        0. Android开发常用设计模式;

        1. Android中单例模式;

        2. Android中建造者(builder)模式;

        3. Android中观察者模式;

        4. Android中原型模式;

        5. Android中策略模式;

        6. Android中工厂模式;

        7. Android中代理模式;

        8. Android中装饰者模式;

        9. Android中适配器模式;




   小白:毛毛哥,我最近在看工厂模式的时候一脸懵逼 Android中工厂模式_第1张图片

   三毛:”我的白,上次在讲观察者模式的时候我就说你接口不熟了,现在工厂模式中还要用到抽象类,估计你也不熟,你还是把接口和抽象类搞清楚,弄熟在看工厂模式吧,不然晕乎乎,看不懂是正常的”

   小白:Android中工厂模式_第2张图片给我讲讲嘛,可爱的毛毛哥,甩甩的毛毛哥,裤裤的毛毛哥,风一样的毛毛哥


   三毛:这里写图片描述 唉,那我就尽量有多简单就多简单给你讲讲吧,谁叫你是我的白呢


一、常见需求场景

   三毛:”小白,像平常的第三方登陆,如下面的图,要是给你模拟一下,你打算怎么去做”

Android中工厂模式_第3张图片


二、基本解决方法

   小白:毛毛哥 Android中工厂模式_第4张图片 欺负我不会其他写法,呜呜~~,我只能像下面那样去写

//写个登陆接口
public interface ILogin {
    void login();
}

//QQ登陆
public class QQLogin implements ILogin {
    @Override
    public void login() {
        System.out.println("QQ登陆...");
    }
}

//WeiXin登陆
public class WeiXinLogin implements ILogin {
    @Override
    public void login() {
        System.out.println("WeiXin登陆...");
    }
}


//使用
new QQLogin().login();
new WeiXinLogin().login();


三、基本解决方法存在的问题

   三毛:“上面你自己看觉得没啥问题,但是我看漏洞百出喔”

   小白:这里写图片描述

   三毛:“假设在登陆前,要做10个步骤的操作处理,才能进一步登陆,你上面代码是不是像下面这样”

//写个登陆接口
public interface ILogin {
    void login();
}

//QQ登陆
public class QQLogin implements ILogin {
    @Override
    public void login() {
        System.out.println("QQ登陆...");
    }

    //操作A、B、C、D....后面其他省略了
    public void A(){}
}

//WeiXin登陆
public class WeiXinLogin implements ILogin {
    @Override
    public void login() {
        System.out.println("WeiXin登陆...");
    }
     //操作A、B、C、D....后面其他省略了
    public void A(){}
}


//使用
QQLogin qqLogin = new QQLogin();
WeiXinLogin weiXinLogin = new WeiXinLogin();

qqLogin.A();
qqLogin.B();
...
qqLogin.login();

weiXinLogin.A();
weiXinLogin.B();
...
weiXinLogin.login();

   三毛:“假设有10个界面(或者更多)都要用到登陆,你岂不是要10个界面都写那么多代码,你不累啊”

   小白:我没想过登陆前还有可能存在那么多操作,所以就把对象new出来直接用了- -

四、工厂模式写法

工厂模式定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。


   三毛:“不扯蛋了,进入主题,工厂模式分为下面4种,我们一个一个来解释”


1、静态工厂模式
            ==>静态工厂和简单工厂其实没啥区别,区别在于是否有static修饰方法
2、简单工厂模式
3、工厂方法模式 —->为了解决某些问题
4、抽象工厂模式 —->为了解决某些问题



1、静态工厂模式(优化小白你的代码)




//多加个工厂类(之前的代码没变)
public class LoginFactory {
    //在你基础上加个包装类,在包装类方法加个static修饰符就是静态工厂模式了(是不是想起了工具类的使用)
    public static ILogin initLogin(String loginType) {
        ILogin iLogin = null;
        switch (loginType) {
            case "QQ":
            //如果在登陆前有多余的操作可以在这里完成
                iLogin = new QQLogin();
                break;
            case "WeiXin":
            //如果在登陆前有多余的操作可以在这里完成
                iLogin = new WeiXinLogin();
                break;
            default:
                iLogin = null;
                break;
        }
        return iLogin;
    }

   /* 
   第二种写法(通过反射)
   public ILogin initLogin2(Class clas) {
        ILogin iLogin = null;
        try {
            iLogin = clas.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return iLogin;
    }*/
}

//使用
 ILogin qqLogin = LoginFactory.initLogin("QQ");
 ILogin weiXinLogin = LoginFactory.initLogin("WeiXin");

 qqLogin.login();
 weiXinLogin.login();



2、简单工厂模式

   三毛:“在上面代码中去掉static修饰方法,就是简单工厂模式了,看,多简单”

public class LoginFactory {
   //去掉了static
    public ILogin initLogin(String loginType) {
        ILogin iLogin = null;
        switch (loginType) {
            case "QQ":
            //如果在登陆前有多余的操作可以在这里完成
                iLogin = new QQLogin();
                break;
            case "WeiXin":
            //如果在登陆前有多余的操作可以在这里完成
                iLogin = new WeiXinLogin();
                break;
            default:
                iLogin = null;
                break;
        }
        return iLogin;
    }

   /* 
   第二种写法(通过反射)
   public ILogin initLogin2(Class clas) {
        ILogin iLogin = null;
        try {
            iLogin = clas.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return iLogin;
    }*/
}

//使用
 LoginFactory loginFactory = new LoginFactory();
 ILogin qqLogin = loginFactory .initLogin("QQ");
 ILogin weiXinLogin = loginFactory .initLogin("WeiXin");

 qqLogin.login();
 weiXinLogin.login();

   小白: Android中工厂模式_第5张图片

   三毛:这里写图片描述我很认真的在给你讲,要是怀疑你可以去看看大话设计模式中的简单工厂模式”

   小白:老哥,我错了

   三毛:“静态工厂模式或简单工厂模式如果考虑设计模式的开闭原则(对扩展开放,对修改封闭)就要在进一步优化,相当于升级成工厂方法模式”

   小白:完全听不懂啊,为什么还要优化简单工厂模式或静态工厂模式

   三毛:”当你把项目的登陆模块做完后,老板和你说QQ和微信登陆还不够,把其他第三方登陆都给我接上去,这时候除了添加ALogin、BLogin、CLogin…外,是不是还要在工厂类里把所有第三方登陆判断给加上去,有没有挺难看?还有最主要一点就是违反了设计模式的开闭原则,当需求变动后你就修改工厂类”

   小白:Android中工厂模式_第6张图片我觉得不难看哇,就算违反了设计模式的开闭原则,但也没啥影响吧

   三毛:这里写图片描述 这个你自己去看看设计模式6大原则中的开闭原则吧,不想和你啰嗦了”

   小白:哼,那也得等你给我讲完这个我在去看


3、工厂方法模式

//上面其他代码不变,我们只把原来简单工厂模式或静态工厂模式工厂类优化一下

//把原来工厂类的方法抽取成接口(也可以是抽象类)
public interface IFactory {
    ILogin initLogin();
}

//QQ工厂类
public class QQFactory implements IFactory{
    @Override
    public ILogin initLogin() {
        //如果在登陆前有多余的操作可以在这里完成
        return new QQLogin();
    }
}
//WeiXin工厂类
public class WeiXinFactory implements IFactory {
    @Override
    public ILogin initLogin() {
    //如果在登陆前有多余的操作可以在这里完成
        return new WeiXinLogin();
    }

}
//其他第三方登陆一样的,这里省略...


//使用
QQFactory qqFactory = new QQFactory();
WeiXinFactory weiXinFactory = new WeiXinFactory();

qqFactory.initLogin().login();
weiXinFactory.initLogin().login();

   小白:咦,这么简单啊,就把原来工厂类的方法抽取成接口而已啊

   三毛:“你以为有多难呢,你说不太懂,肯定是因为你接口和抽象类不太熟而已”

   小白:Android中工厂模式_第7张图片

   三毛:”这样不管老板要加几个第三方登陆都没问题了,我们也不用去修改工厂类了,因为一个第三方登陆就是一个工厂类了嘛”

   小白:Android中工厂模式_第8张图片

   三毛:“小白,如果我这时候在加多一个需求,每一个第三方登陆都要绑定支付宝支付和微信支付,你会怎么做”

   小白:我想到2种办法

1.在每个第三方登陆工厂直接加支付宝支付和微信支付方法,代码如下

//QQ工厂类
public class QQFactory implements IFactory{
    @Override
    public ILogin initLogin() {
        //如果在登陆前有多余的操作可以在这里完成
        return new QQLogin();


 //在这里加多2个方法支付宝支付和微信支付
  public void pay() {
        System.out.println("支付宝支付...");
    }
  public void pay() {
        System.out.println("微信支付...");
    }
}


//WeiXin工厂类
public class WeiXinFactory implements IFactory {
    @Override
    public ILogin initLogin() {
    //如果在登陆前有多余的操作可以在这里完成
        return new WeiXinLogin();
    }

//在这里加多2个方法支付宝支付和微信支付
  public void aliPay() {
        System.out.println("支付宝支付...");
    }
  public void weiXinPay() {
        System.out.println("微信支付...");
    }
}

//其他第三方登陆一样的,这里省略...

//使用
QQFactory qqFactory = new QQFactory();
WeiXinFactory weiXinFactory = new WeiXinFactory();

qqFactory.initLogin().login();
weiXinFactory.initLogin().login();

qqFactory.aliPay();
qqFactory.weiXinPay();

weiXinFactory.aliPay();
weiXinFactory.weiXinPay();

   三毛:”嗯,这个,确实可以满足新加的需求,但是你都用了工厂模式了,还用这么low的方法,偶的白”

   小白:那就用第二种方法

2.多加个支付接口,修改下工厂,如下

//新加个支付接口(也可以是抽象类)
public interface IPay {
    void pay();
}

//支付宝支付
public class AliPay implements IPay {
    @Override
    public void pay() {
        System.out.println("支付宝支付...");
    }
}

//微信支付
public class WeiXinPay implements IPay {
    @Override
    public void pay() {
        System.out.println("微信支付...");
    }
}

//---------------------修改下工厂类-----------------//


//在工厂方法模式中把原来工厂类的接口修改下(也可以是抽象类)
public interface IFactory {
    ILogin initLogin();
    //新加2个支付绑定
    IPay bindAliPay();
    IPay bindWeiXinPay();
}

//QQ工厂类
public class QQFactory implements IFactory{
    @Override
    public ILogin initLogin() {
        //如果在登陆前有多余的操作可以在这里完成
        return new QQLogin();


  //实现了新加的2个支付方法
    @Override
    IPay bindAliPay() {
        return new AliPay();
    }

    @Override
    IPay bindWeiXinPay() {
        return new WeiXinPay();
    }
}

//微信工厂类也是一样的,这里省略了...


//使用
QQFactory qqFactory = new QQFactory();
WeiXinFactory weiXinFactory = new WeiXinFactory();

qqFactory.initLogin().login();
weiXinFactory.initLogin().login();
//QQ
qqFactory.bindAliPay().pay();
qqFactory.bindWeiXinPay().pay();
//微信
weiXinFactory.bindAliPay().pay();
weiXinFactory.bindWeiXinPay().pay();

   三毛:”嗯,这一种方式使用了前面工厂方法模式思想,但是也会有一点点问题”

   小白:有啥问题喔

   三毛:”现在上面的工厂方法模式是一个第三方登陆对应一个工厂,然后工厂里面实现了初始化登陆和绑定支付的方法,我们也知道10个第三方登陆就有10个工厂类(10个啊,或者更多)”

   小白:有点明白了毛毛哥意思了,一个第三方登陆对应一个工厂类虽然管理维护方便了,如果第三方登陆过多,也会造成类爆炸…

   三毛:”嗯,如果一开始我们就换个角度去考虑设计的话,就会好很多”

   小白:怎样换个角度设计呢

   三毛:”一开始我们只考虑到只有初始化登陆(initLogin)一个类型的东西,所以设计成一个第三方登陆对应一个工厂类,现在变成初始化登陆和绑定支付2个类型的东西了,我们可以想象,N个第三方登陆和2个类型(初始化登陆和绑定支付)的东西对比,数量那个多呢”

   小白:毛毛哥,那还用问,肯定是N个第三方登陆多啊

   三毛:”嗯,因为这时候有初始化登陆(initLogin)和绑定支付2个不同类型的东西,我们可以考虑使用抽象工厂模式(抽象工厂模式思路)”


4、抽象工厂模式

//---------------------之前没变的代码区域---------------------//


//登陆接口(没变)也可以是抽象类
public interface ILogin {
    void login();
}

//QQ登陆实现(没变)
public class QQLogin implements ILogin {
    @Override
    public void login() {
        System.out.println("QQ登陆...");
    }
}

//WeiXin登陆实现(没变)
public class WeiXinLogin implements ILogin {
    @Override
    public void login() {
        System.out.println("微信登陆...");
    }
}
//其他第三方登陆同上,省略...


//上面定义的支付接口(没变)也可以是抽象类
public interface IPay {
    void pay();
}

//支付宝支付实现(没变)
public class AliPay implements IPay {
    @Override
    public void pay() {
        System.out.println("支付宝支付...");
    }
}

//微信支付实现(没变)
public class WeiXinPay implements IPay {
    @Override
    public void pay() {
        System.out.println("微信支付...");
    }
}
//其他支付同上,省略...

//---------------------之前没变的代码区域end---------------------//



//----------------工厂类和工厂接口换个角度设计(彻底改头换脸)----------------//



//工厂接口(之前只有登陆一种类型方法,现在从登陆和绑定支付2种类型考虑设计接口)也可以是抽象类
public interface IFactory {                      // public interface IFactory {
     ILogin initQQLogin();     //======和之前对比》//       ILogin initLogin();
     ILogin initWeiXinLogin();                   //  }

     IPay bindAliPay();
     IPay bindWeiXinPay();
}

//工厂实现类
public class FactoryImp implements IFactory{
    @Override
    public ILogin initQQLogin() {
        return new QQLogin();
    }

    @Override
    public ILogin initWeiXinLogin() {
        return new WeiXinLogin();
    }

    @Override
    public IPay bindAliPay() {
        return new AliPay();
    }

    @Override
    public IPay bindWeiXinPay() {
        return new WeiXinPay();
    }


}

  //使用
  FactoryImp factoryImp = new FactoryImp();

  factoryImp.initQQLogin().login();
  factoryImp.initWeiXinLogin().login();

  factoryImp.bindAliPay().pay();
  factoryImp.bindWeiXinPay().pay();

  小白:毛毛哥,上面就是抽象工厂模式嘛,我觉得和‘工厂方法模式’没啥区别吖

  三毛:“怎么会没区别呢 这里写图片描述

  小白:Android中工厂模式_第9张图片

  三毛:“我这里就给你对比一下上面的工厂方法模式和抽象工厂模式区别”


        工厂方法模式                    抽象工厂方法模式
1.只有一个产品结构(登陆实例和登陆工厂都只有登陆类型)      1.多个产品结构(登陆和支付类型)
2.只有一个抽象产品类(登陆接口)                 2.多个抽象产品类(登陆和支付接口)
3.每个具体工厂只能创建一个具体产品(如QQ工厂对应QQ登陆)   3.每个具体工厂可以创建多个具体产品(登陆和支付2个不同类型的产品中的多个登陆和支付)

  小白:Android中工厂模式_第10张图片

  三毛:“抽象工厂中如果要添加新的第三方登陆和其他支付,我们就可以在写多个新的接口,在写个新的工厂,像下面,类减少了,也符合对扩展开放,对修改封闭”

//新加的新浪微博登陆
public class SinaLogin implements ILogin {
    @Override
    public void login() {
        System.out.println("新浪微博登陆...");
    }
}
//新加的银行支付
public class BankPay implements IPay {
    @Override
    public void pay() {
        System.out.println("银行支付...");
    }
}

//新加的接口(也可以是抽象类)
public interface INewFactory {
    ILogin initSinaLogin();

    IPay bindBankPay();
}

//新加的抽象工厂类,在原来基础上面新加的接口,搞定
public class NewFactoryImp implements IFactory,INewFactory{
    @Override
    public ILogin initQQLogin() {
        return new QQLogin();
    }

    @Override
    public ILogin initWeiXinLogin() {
        return new WeiXinLogin();
    }

    @Override
    public IPay bindAliPay() {
        return new AliPay();
    }

    @Override
    public IPay bindWeiXinPay() {
        return new WeiXinPay();
    }


    @Override
    public ILogin initSinaLogin() {
        return new SinaLogin();
    }

    @Override
    public IPay bindBankPay() {
        return new BankPay();
    }
}

//使用还是一样,省略...


五、工厂模式和普通写法区别


1、将对象的创建统一起来便于维护扩展和整体把控;

2、对扩展开放,对修改封闭;

3、因为使用了很多接口设计,降低了耦合(所有设计模式不基本都为了解耦嘛)

你可能感兴趣的:(开发常用的设计模式)