文档章节

Android设计模式之工厂模式--Factory

恒源祥
 恒源祥
发布于 2016/12/29 16:13
字数 2584
阅读 8
收藏 0

一.概述

平时做项目跟使用第三方类库的时候经常会用到工厂模式.什么是工厂模式,简单来说就是他的字面意思.给外部批量提供相同或者不同的产品,而外部不需要关心工厂是如何创建一个复杂产品的过程.所以工厂模式可以降低模块间的耦合,同时可以提高扩展性(当有新的产品出现时,只需要扩展工厂就行了,上层模块不敏感).

工厂模式根据抽象的角度和层级的不同可以分为两种模式:

1.工厂方法模式 (Factory Method)

2.抽象工厂模式 (Abstract Factory)

二.实现

1.工厂方法模式

工厂方法模式的特点是:

一个抽象产品类(或接口),派生(或实现)多个真实产品类

一个抽象工厂类(或接口),派生(或实现)多个真实工厂类

一般来说标准的工厂方法模式需要一个工厂只生产一种产品,那么当产品种类特别多的时候工厂的数量就特别多,所以通常会使用一些工厂方法模式的变种.

1.)标准工厂方法模式

首先先介绍一下标准的工厂方法模式,不带任何的变种.以工厂生产不同操作系统的手机为例.

建立一个产品接口,提供一个获取系统信息的方法.

 

?

1

2

3

4

5

6

/**

 * Created by jesse on 15-8-17.

 */

public interface IPhone {

    public void getOS();

}

再根据IPhone接口实现Android,IOS,Blackberry三种手机.

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

public class AndroidPhone implements IPhone {

    private final String TAG = AndroidPhone.class.getSimpleName();

    @Override

    public void getOS() {

        Log.i(TAG, im Android);

    }

}

public class IosPhone implements IPhone {

    private final String TAG = IosPhone.class.getSimpleName();

    @Override

    public void getOS() {

        Log.i(TAG, im IOS);

    }

}

public class BlackBerryPhone implements IPhone {

    private final String TAG = BlackBerryPhone.class.getSimpleName();

    @Override

    public void getOS() {

        Log.i(TAG, im BlackBerry);

    }

}

标准的工厂方法模式都需要有抽象的工厂接口或者基类.

?

1

2

3

public abstract class IGenerator {

    public abstract IPhone generatePhone(String flag) throws Exception;

}

通过基类或者接口来实现真实的工厂类,这里需要注意跟简单工厂模式的不同,标准的工厂方法模式里面一个工厂只生产一个产品,所以这里要根据产品的种类划分出来三个工厂,分别生产三种不同的产品.这种设计思想非常契合单一职责原则.

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

public class AndroidGenerator extends IGenerator {

    @Override

    public IPhone generatePhone() {

        return new AndroidPhone();

    }

}

public class IOSGenerator extends IGenerator {

    @Override

    public IPhone generatePhone() {

        return new IosPhone();

    }

}

public class BlackberryGenerator extends IGenerator {

    @Override

    public IPhone generatePhone() {

        return new BlackBerryPhone();

    }

}

在客户端从工厂中获得产品并使用的过程中都是通过接口进行访问的,在创建产品的阶段有效得降低了使用者和产品之间的耦合度.

 

?

1

2

3

4

5

6

7

8

9

10

11

IPhone android, ios, bb;

IGenerator androidGenerator, iosGenerator, bbGenerator;

androidGenerator = new AndroidGenerator();

iosGenerator = new IOSGenerator();

bbGenerator = new BlackberryGenerator();

android = androidGenerator.generatePhone();

ios = iosGenerator.generatePhone();

bb = bbGenerator.generatePhone();

android.getOS();

ios.getOS();

bb.getOS();

最终的运行效果显而易见.

 

\
2).简单工厂模式

接着分析一下简单工厂模式,这是最简单的变种,也叫做静态工厂方法模式,从这个名字就可以看出工厂的方法是静态的.既然工厂方法是静态的,那么工厂就不能通过继承进行扩展,如果有新增的产品,就只能在静态方法里面做修改所以从这个角度来说简单工厂模式是不符合开闭原则的.

因为这是静态工厂方法模式,所以工厂类就没有接口或者虚基类来提供抽象.通过不同的Flag来初始化不同的产品.

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

public class PhoneGenerator{

    public final static String GENERATE_IOS = generate_ios;

    public final static String GENERATE_ANDROID = generate_android;

    public final static String GENERATE_BLACKBERRY = generate_blackberry;

 

    public static IPhone generatePhone(String flag) throws Exception {

        IPhone iPhone = null;

        switch (flag){

            case GENERATE_ANDROID:

                iPhone =  new AndroidPhone();

                break;

            case GENERATE_IOS:

                iPhone =  new IosPhone();

                break;

            case GENERATE_BLACKBERRY:

                iPhone =  new BlackBerryPhone();

                break;

            default:

                throw new Exception(UNDEFINED FLAG);

        }

        return iPhone;

    }

}

对外部来说要使用工厂只需要把目标产品类传过去就行了.运行结果跟1)中的是一样的.

 

?

1

2

3

4

5

6

7

IPhone android, ios, bb;

android = PhoneGenerator.generatePhone(PhoneGenerator.GENERATE_ANDROID);

ios = PhoneGenerator.generatePhone(PhoneGenerator.GENERATE_IOS);

bb = PhoneGenerator.generatePhone(PhoneGenerator.GENERATE_BLACKBERRY);

android.getOS();

ios.getOS();

bb.getOS();

3)结合反射的应用

假设需要加入一种搭载win10系统的手机,标准的工厂方法模式需要重新派生出来一个新的工厂来给客户使用,简单工厂模式也需要新增新的flag和case判断去构造新的手机.有没有什么方法可以尽量避免这些修改呢?当然是有的,这里可以通过使用Class.forName 反射的方式来达到目的.

首先通过泛型来约束输入输出的参数类型,把异常抛到上层去处理并实现具体的工厂.

 

?

1

2

3

public abstract class IGenerator {

    public abstract <t extends="" iphone="">T generatePhone(Class<t> clazz) throws Exception;

}</t></t>

?

1

2

3

4

5

6

7

public class PhoneGenerator extends IGenerator {

    public <t extends="" iphone="">T generatePhone(Class<t> clazz) throws Exception {

        IPhone iPhone = null;

        iPhone = (IPhone) Class.forName(clazz.getName()).newInstance();

        return (T)iPhone;

    }

}</t></t>

通过这种装载的方式去初始化产品就可以达到上面描述的需求,可以根据需求直接添加一个实现了IPhone接口的WindowsPhone产品而不需要修改工厂,客户就可以直接从工厂拿到WindowsPhone的手机去使用了.

 

4)产品类私有构造应用

产品类私有构造应用其实更偏向与一种规范.既然使用工厂模式了,那就是这些手机全部都要在工厂内部创建出来.这种应用就做了限制,使用私有构造就不允许外部通过new的方式来创建,而工厂则通过反射和更改访问权限来创建产品.当然这个时候外部也可以通过同样的方式来创建对象,所以说这个应用更偏向于一种团队规范.

 

?

1

2

3

4

5

6

7

8

9

public class PhoneGenerator extends IGenerator {

    public <t extends="" iphone="">T generatePhone(Class<t> clazz) throws Exception {

        IPhone iPhone = null;

        Class phone = Class.forName(clazz.getName());

        phone.getDeclaredConstructor().setAccessible(true);

        iPhone = (IPhone) phone.newInstance();

        return (T)iPhone;

    }

}</t></t>

5)缓存对象

对于那些创建起来特别消耗资源或者特别复杂的对象,可以使用下面的方式来进行一个长期的缓存.对于那些有访问数量需求的对象也可以建立缓存List,通过设置最大创建数来控制对象量级的峰值.例如JDBC的最大连接数等.

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public class PhoneGenerator extends IGenerator{

    private Map<string, iphone=""> map = new HashMap<>();

    @Override

    public <t extends="" iphone=""> T generatePhone(Class<t> clazz) throws Exception{

        IPhone iPhone = null;

        if (map.containsKey(clazz.getName()))

            iPhone = map.get(clazz.getName());

        else {

            iPhone = (IPhone) Class.forName(clazz.getName()).newInstance();

            map.put(clazz.getName(), iPhone);

        }

        return (T) iPhone;

    }

}</t></t></string,>

2.抽象工厂模式

抽象工厂模式的特点:

多个抽象产品类(或接口),派生(或实现)多个真实产品类

一个抽象工厂类(或接口),派生(或实现)多个真实工厂类

抽象工厂模式其实也算是工厂方法模式的一种延伸,在工厂方法模式中所有的产品都是一个系列的,都是从IPhone那里实现出的不同真实产品,所以对于外部来说他们都是手机产品,只需要关心手机的抽象接口就行了.然而又多个业务种类,并且这些业务有些依赖关系的时候,这种情况下使用的工厂模式就是抽象工厂模式.

接着在抽象方法模式里面的例子,在抽象工厂模式中我们需要再多开一种产品,那就平板吧,而平板又分为Android平板和IOS平板(这里偷懒黑莓平板就不写了),并且平板跟手机有很多共同的地方,例如相同的OS硬件设计等.既然是一个新的产品线了,那么还是先抽象出来平板的接口来.还是老样子,打印一下自己是什么系统的.

 

?

1

2

3

public interface IPad {

    public void getBrand();

}

接着通过IPad接口来实现两个不同的平板.

 

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public class AndroidPad implements IPad {

    private final String TAG = AndroidPad.class.getSimpleName();

    @Override

    public void getBrand() {

        Log.i(TAG, im Android pad);

    }

}

public class IOSPad implements IPad {

    private final String TAG = IOSPad.class.getSimpleName();

    @Override

    public void getBrand() {

        Log.i(TAG, im IOS phone pad);

    }

}

在抽象工厂的接口的时候还是继续使用泛型来创建了,这样也省的派生出来几个不同的工厂.

 

 

?

1

2

3

4

public abstract class IGenerator {

    public abstract <t extends="" iphone="">T generatePhone(Class<t> clazz) throws Exception;

    public abstract <t extends="" ipad="">T generatePad(Class<t> clazz) throws Exception;

}</t></t></t></t>

?

1

2

3

4

5

6

7

8

9

10

11

12

13

public class ProductGenerator extends IGenerator{

    @Override

    public <t extends="" iphone=""> T generatePhone(Class<t> clazz) throws Exception{

        IPhone iPhone = (IPhone) Class.forName(clazz.getName()).newInstance();

        return (T) iPhone;

    }

 

    @Override

    public <t extends="" ipad=""> T generatePad(Class<t> clazz) throws Exception {

        IPad iPad = (IPad) Class.forName(clazz.getName()).newInstance();

        return (T) iPad;

    }

}</t></t></t></t>

假设有一个客户需要来我厂定制移动产品,A套餐中包含一个IOS手机和一个Android的平板,B套餐中包含一个Android手机和一个IOS平板.而这个套餐规则可以通过工厂进行约束.这样工厂就能胜任完成这个需求的任务了.

 

然而恰恰因为抽象工厂模式支持多种产品线,结果导致需要扩展一条新的产品的时候就会比较麻烦.假设需要新增一个屏幕贴膜产品,并且给每个出厂的带屏幕的产品都配一个.那么要做的修改不仅仅是要添加贴膜这个产品,还要修改从工厂的抽象到工厂的实现,还要修改工厂的约束.这是不符合开闭原则的.但是如果只是扩展一个产品的子系列,例如要新增一个windows平板,抽象工厂模式和工厂方法模式一样根本不需要修改工厂抽象和工厂实现,只需要新增产品就行了.

© 著作权归作者所有

恒源祥
粉丝 16
博文 109
码字总数 97221
作品 0
深圳
Android工程师
私信 提问
代理模式(Proxy Pattern):动态代理 - 最易懂的设计模式解析

前言 今天我来全面总结开发中最常用的设计模式 - 代理模式中的动态代理模式 其他设计模式介绍 1分钟全面了解“设计模式” 单例模式(Singleton) - 最易懂的设计模式解析 简单工厂模式(Sim...

Carson_Ho
2018/04/09
0
0
Android 架构师9 设计模式之策略模式

前言 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们之间可以相互替换。这些策略算法是相同行为的不同实现。 需求 三国故事中,刘备要到江东娶孙权的妹妹孙尚香,由于这行...

zhang_pan
2018/04/26
0
0
[Andriod设计模式之旅]——Builder模式

版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/u013132758。 https://blog.csdn.net/u013132758/article/details/78764592 前言 具体介绍Builder设计模式之前,首先我们...

紫雾凌寒
2017/12/10
0
0
Android 网络编程 目录

Android 网络编程 目录 Android 网络编程1 Http协议 Android 网络编程2 Okhttp缓存机制 Android 网络编程3 Java NIO to be continued... Android 架构师之路 目录 Android 架构师之路1 UML图...

香沙小熊
2018/06/21
0
0
设计模式之抽象工厂模式(创建型)

模式定义 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。 模式角色 抽象...

smileNicky
01/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Django笔记-3-模型-20190526

简介 django为各种数据库提供了很好的支持,django对这些数据库提供了统一的调用API;可以根据不同的也无需求选择不同的数据库; 配置数据库 在setting.py文件中配置数据库 DATABASES = { ...

Frank1126lin
14分钟前
0
0
OSChina 周日乱弹 —— 程序员做噩梦

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @-冰冰棒- :#今日歌曲推荐# 手嶌葵《Kiss The Girl》 《Kiss The Girl》- 手嶌葵 手机党少年们想听歌,请使劲儿戳(这里) @Sharon啊 :今天...

小小编辑
47分钟前
114
6
Another app is currently holding the yum lock; waiting for it to exit...

Another app is currently holding the yum lock; waiting for it to exit... The other application is: PackageKit Memory : 153 M RSS (266 MB VSZ) Started: Thu Jul 12 00:03......

圣洁之子
55分钟前
2
0
FastDateFormat 研究

FastDateFormat 对缓存的利用,其实就是用ConcurrentHashMap 做了一个map类型的缓存 public F getInstance(final String pattern, TimeZone timeZone, Locale locale) { Validate......

暗中观察
今天
3
0
Android双向绑定原理简述

Android双向绑定原理简述 双向绑定涉及两个部分,即将业务状态的变化传递给UI,以及将用户输入信息传递给业务模型。 首先我们来看业务状态是如何传递给UI的。开启dataBinding后,编译器为布局...

tommwq
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部