# 常见设计模式三:工厂模式
[toc]
## 前言
前面分别介绍了单例模式和构造者模式,实际开发中,这两个模式的使用概率是很高的,还有一个使用率很高的设计模式就是工厂模式。
今天来了解下工厂模式,工厂模式属于创建性模式的一种,而工厂模式本身又被大家分为三种:
1. 简单工厂模式
2. 工厂方法模式
3. 抽象工厂模式
## 一、简单工厂模式
简单工厂模式其实更多的是我们平时开发过程中的一个开发习惯,比如在一个类中提供一个静态方法,根据传递进来的不同参数,返回具体的对象。
下面以手机支付为例做说明。
抽象支付功能:
```java
public interface IPay {
void pay(Double money);
}
```
具体实现ApplePay 和 HuaWeiPay:
```java
public class ApplePay implements IPay {
@Override
public void pay(Double money) {
System.out.println("使用 ApplePay 支付了 " + money + "元");
}
}
public class HuaWeiPay implements IPay {
@Override
public void pay(Double money) {
System.out.println("使用 HuaWeiPay 支付了 " + money + "元");
}
}
```
获取支付方式的工厂:
```java
public class PayFactory {
public static IPay getPay(String pay) {
switch (pay) {
case "huawei":
return new HuaWeiPay();
case "apple":
return new ApplePay();
default:
return new ApplePay();
}
}
}
```
测试类:
```java
public class PayMain {
public static void main(String[] args) {
IPay pay = PayFactory.getPay("apple");
pay.pay(1000d);
pay = PayFactory.getPay("huawei");
pay.pay(5000d);
}
}
```
结果:
![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200308161841.png)
可以看到:在支付工厂中提供了一个静态方法,根据传入的支付类型的不同,返回了不同的支付对象,用来完成最终的支付操作,这就是简单工厂模式,下面来看下工厂方法模式。
## 二、工厂方法模式
在工厂方法模式中,我们取消了统一创建对象的 PayFactory ,而是提供一个创建对象的抽象,把具体的创建任务交给具体的工厂,比如获取苹果支付的对象,用 ApplePayFactory ,获取华为支付的对象用 HuaWeiPayFactory
还以上面的获取支付对象为例:做出以下改变:
修改 PayFactory 为:
```java
public interface PayFactory {
IPay create();
}
```
创建 ApplePayFactory 、 HuaWeiPayFactory 用来分别创建 支付对象:
```java
public class ApplePayFactory implements PayFactory {
@Override
public IPay create() {
return new ApplePay();
}
}
public class HuaWeiPayFactory implements PayFactory {
@Override
public IPay create() {
return new HuaWeiPay();
}
}
```
测试:
```java
public class MethodFactoryMain {
public static void main(String[] args) {
IPay pay ;
HuaWeiPayFactory huaWeiPayFactory = new HuaWeiPayFactory();
pay = huaWeiPayFactory.create();
pay.pay(1000d);
ApplePayFactory applePayFactory = new ApplePayFactory();
pay = applePayFactory.create();
pay.pay(5000d);
}
}
```
结果:
![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200308162645.png)
可以看到和简单工厂的主要区别就是,不再把所有的创建支付方式放在一个工厂类中,而是统一定义一个获取支付方式的工厂,然后由不同的支付 Pay 构建不同的工厂,比如华为支付工厂,苹果支付工厂。
在简单工厂模式下,如果我们想添加一个 Oppo 支付,那么就需要去改变 PayFactory 类,去增加一个类型判断,这样如果不利于项目代码的扩展和稳定性,
而在工厂方法下,只需要定义一个获取支付对象的工厂,由不同的厂家去定义自己的支付工厂,这样就算是添加一个 Oppo 支付,也只用创建 OppoPay 和 OppoPayFactory 就行,不用修改顶层的抽象:
```java
public class OppoPay implements IPay {
@Override
public void pay(Double money) {
System.out.println("使用 OppoPay 支付了 " + money + "元");
}
}
public class OppoPayFactory implements PayFactory {
@Override
public IPay create() {
return new OppoPay();
}
}
public class MethodFactoryMain {
public static void main(String[] args) {
IPay pay;
HuaWeiPayFactory huaWeiPayFactory = new HuaWeiPayFactory();
pay = huaWeiPayFactory.create();
pay.pay(1000d);
ApplePayFactory applePayFactory = new ApplePayFactory();
pay = applePayFactory.create();
pay.pay(5000d);
OppoPayFactory oppoPayFactory = new OppoPayFactory();
pay = oppoPayFactory.create();
pay.pay(7000d);
}
}
```
结果:
![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200308163243.png)
可以看到,工厂方法模式在不影响原来代码的情况下,扩展性是很好的。
下面再来看下抽象工厂模式
## 三、抽象工厂模式
抽象工厂模式大概分为四种部分:
1. AbstractFactory 抽象工厂,声明了一组创建对象的方法
2. ConcreteFactory 工厂的具体实现,实现了在抽象工厂中声明的创建对象的方法,生成一组对象
3. AbstractProduct 抽象产品,为每种对象声明接口,在其中声明了该对象具有的业务方法
4. ConceteeProduct 具体产品,定义工厂要实现的对象。
下面还以支付为例。
我们知道,在不同手机平台上,分别于有不同的支付方式,比如
苹果手机有的支付方式:ApplyPay、支付宝、微信支付等等
HuaWei 手机有的支付方式:HuaWeiPay、支付宝、微信支付等等
大致分为两类:
1. 手机支付(各种手机Pay)
2. 软件支付(支付宝、微信等)
创建抽象产品:手机支付接口和软件支付接口:
```java
public interface IPhonePay {
void pay(Double money);
}
public interface ISoftPay {
void pay(Double money);
}
```
创建抽象工厂:
```java
public interface IPayFactory {
IPhonePay createPhonePay();
ISoftPay createSoftPay();
}
```
苹果和华为分别对 手机支付接口的实现:
```java
public class ApplyPay implements IPhonePay {
@Override
public void pay(Double money) {
System.out.println("苹果手机 使用手机支付了 " + money + "元");
}
}
public class HuaWeiPay implements IPhonePay {
@Override
public void pay(Double money) {
System.out.println("华为手机 使用手机支付了 " + money + "元");
}
}
```
苹果和华为分别对 软件支付接口的实现:
```java
public class AppleSoftPay implements ISoftPay {
@Override
public void pay(Double money) {
System.out.println("苹果手机 使用软件(支付宝/微信)支付了 " + money + "元");
}
}
public class HuaWeiSoftPay implements ISoftPay {
@Override
public void pay(Double money) {
System.out.println("华为手机 使用软件(支付宝/微信)支付了 " + money + "元");
}
}
```
苹果手机、华为对支付方式的实现,具体实现抽象工厂:
```java
public class ApplyPayFactory implements IPayFactory {
@Override
public IPhonePay createPhonePay() {
return new ApplyPay();
}
@Override
public ISoftPay createSoftPay() {
return new AppleSoftPay();
}
}
public class HuaWeuPayFactory implements IPayFactory {
@Override
public IPhonePay createPhonePay() {
return new HuaWeiPay();
}
@Override
public ISoftPay createSoftPay() {
return new HuaWeiSoftPay();
}
}
```
测试类:
```java
public class Main {
public static void main(String[] args) {
IPayFactory payFactory;
payFactory = new ApplyPayFactory();
payFactory.createPhonePay().pay(1000d);
payFactory.createSoftPay().pay(2000d);
payFactory = new HuaWeuPayFactory();
payFactory.createPhonePay().pay(3000d);
payFactory.createSoftPay().pay(4000d);
}
}
```
结果:
![](https://markdown-1258186581.cos.ap-shanghai.myqcloud.com/20200308165634.png)
可以看到在最后的使用中,我们只用分别针对苹果手机和华为手机创建支付工厂,然后就可以使用使用不同手机的各种支付功能,如果这个时候 Oppo 又来凑热闹,那么我们就可以单独创建 OppoPhonePay、OppoSoftPay、OppoPayFactory 就可以了。
其实经过和上面工厂方法的对比可以大致可以看出:
**工厂方法模式是针对方法的工厂**
**抽象工厂模式是针对对象的工厂**
工厂模式就讲到这里了,还是需要平时工作中仔细揣摩才行。
- Java 面试题
- String、StringBuffer、StringBuilder 的区别?
- Java 中的四种引用
- 接口和抽象类的本质区别
- 集合框架
- 集合概述
- ArrayList 源码分析
- LinkedList 源码分析
- HashMap 源码分析
- LinkedHashMap 源码分析
- Android提供的 LruCache 的分析
- LinkedList 和 ArrayList 的区别
- 多线程
- 实现多线程的几种方式
- 线程的几种状态
- Thread 的 start() 和 run() 的区别
- sleep() 、yield() 和 wait() 的区别 ?
- notify() 和 notifyAll() 的区别?
- 保证线程安全的方式有哪几种?
- Synchronized 关键字
- volatile 和 synchronized 的区别?
- 如何正确的终止一个线程?
- ThreadLocal 原理分析
- 线程池
- 多线程的三个特征
- 五种线程池,四种拒绝策略,三种阻塞队列
- 给定三个线程如何顺序执行完以后在主线程拿到执行结果
- Java 内存模型
- 判定可回收对象算法
- equals 与 == 操作符
- 类加载机制
- 类加载简单例子
- 算法
- 时间、空间复杂度
- 冒泡排序
- 快速排序
- 链表反转
- IO
- 泛型
- Kolin 面试题
- Android 面试题
- Handler 线程间通信
- Message、MessageQueue、Looper、Handler 的对象关系
- Handler 使用
- Handler 源码分析
- HandlerThread
- AsyncTask
- IntentService
- 三方框架
- Rxjava
- rxjava 操作符有哪些
- 如何解决 RxJava 内存泄漏
- Rxjava 线程切换原理
- map和 flatmap 的区别
- Databinding引起的 java方法大于 65535 的问题
- Glide
- Glide 的缓存原理
- Glide 是如何和生命周期绑定的?不同的Context 有什么区别?
- Glide 、Picasso 、的区别,优劣势,如何选择?
- Jetpack
- 源码分析
- EventBus
- EventBus 源码分析
- RxBus 替代 EventBus
- OkHttp
- OkHttp 源码分析
- OkHttp 缓存分析
- RxPermission
- RxPermission 源码分析
- Retrofit
- create
- Retrofit 源码分析
- 优化
- 启动优化
- 布局优化
- 绘制优化
- 内存优化
- 屏幕适配
- 组件
- Activity
- Frgment
- Service
- ContentProvider
- BroadcastReceiver
- 进程间通信
- Binder机制和AIDL
- AILD 中的接口和普通的接口有什么区别
- in、out、inout 的区别
- Binder 为什么只需要拷贝一次
- 在android中,请简述jni的调用过程
- 生命周期
- Activity 生命周期
- Fragment 生命周期
- Service 生命周期
- onSaveInstanceState() 与 onRestoreIntanceState()
- 前沿技术
- 组件化
- 模块化
- 插件化
- 热更新
- UI - View
- Android 动画
- 事件分发机制
- WebView
- 系统相关
- 谈谈对 Context 的理解
- Android 版本
- App应用启动流程
- App 的打包
- App 的加固
- App 的安装
- Activity 启动流程
- ClassLoader
- Lru 算法加载 Bitmap 三级缓存原理
- Parcelable 和 Serializable 的区别
- Activity的启动流程
- 相关概念
- 网络相关
- Http
- Https
- Http 和 Https 的区别
- 为什么要进行三次握手和四次挥手?
- OkHttp使用Https访问服务器时信任所有证书
- 设计模式
- 单例模式
- 构建者模式
- 工厂模式
- 外观模式
- 代理模式