您的位置:首页 > 移动开发 > Android开发

Android中工厂模式

2017-10-20 16:53 162 查看
设计模式系列:

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

        1. Android中单例模式;

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

        3. Android中观察者模式;

        4. Android中原型模式;

        5. Android中策略模式;

        6. Android中工厂模式;

        7. Android中代理模式;

        8. Android中装饰者模式;

        9. Android中适配器模式;

   小白:毛毛哥,我最近在看工厂模式的时候一脸懵逼 


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

   小白:

给我讲讲嘛,可爱的毛毛哥,甩甩的毛毛哥,裤裤的毛毛哥,风一样的毛毛哥

   三毛:

唉,那我就尽量有多简单就多简单给你讲讲吧,谁叫你是我的白呢

一、常见需求场景

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



二、基本解决方法

   小白:毛毛哥

欺负我不会其他写法,呜呜~~,我只能像下面那样去写

//写个登陆接口
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<? extends ILogin> 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<? extends ILogin> 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();


   小白:


   三毛:

我很认真的在给你讲,要是怀疑你可以去看看大话设计模式中的简单工厂模式”

   小白:老哥,我错了


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

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

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

   小白:

我觉得不难看哇,就算违反了设计模式的开闭原则,但也没啥影响吧

   三毛:

这个你自己去看看设计模式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();


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

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

   小白:


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

   小白:


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

   小白:我想到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();


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

  三毛:“怎么会没区别呢



  小白:


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

        工厂方法模式                    抽象工厂方法模式

1.只有一个产品结构(登陆实例和登陆工厂都只有登陆类型)      1.多个产品结构(登陆和支付类型)

2.只有一个抽象产品类(登陆接口)                 2.多个抽象产品类(登陆和支付接口)

3.每个具体工厂只能创建一个具体产品(如QQ工厂对应QQ登陆)   3.每个具体工厂可以创建多个具体产品(登陆和支付2个不同类型的产品中的多个登陆和支付)

  小白:


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

//新加的新浪微博登陆
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、因为使用了很多接口设计,降低了耦合(所有设计模式不基本都为了解耦嘛)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: