设计模式之工厂模式(Factory)
转载请标明出处:http://blog.csdn.net/shensky711/article/details/53348412
本文出自: 【HansChen的博客】
设计模式系列文章:
设计模式之工厂模式
设计模式之模板方法模式和策略模式
概述
根据依赖倒置原则
,我们知道,我们应优先依赖抽象类而不是具体类。在应用开发过程中,有很多实体类都是非常易变的,依赖它们会带来问题,所以我们更应该依赖于抽象接口,以使我们免受大多数变化的影响。
工厂模式(Factory)
允许我们只依赖于抽象接口就能创建出具体对象的实例,所以在开发中,如果具体类是高度易变的,那么该模式就非常有用。
接下来我们就通过代码举例说明什么是工厂模式
简单工厂模式
假设我们现在有个需求:把一段数据用Wi-Fi或者蓝牙发送出去。
需求很简单是吧?刷刷刷就写下了以下实现:
private String mode; //Wi-Fi|Bluetooth
public void onClick() {
byte[] data = {0x00, 0x01};
if ("Wi-Fi".equals(mode)) {
sendDataByWiFi(data);
} else {
sendDataByBluetooth(data);
}
}
private void sendDataByWiFi(byte[] data) {
// send data by Wi-Fi
}
private void sendDataByBluetooth(byte[] data) {
// send data by Bluetooth
}
但是上面的代码扩展性并不高,违反了开放封闭原则。比如现在又有了个新的需求,需要用zigbee把数据发送出去,就得再新增一个sendDataByZigbee方法了,而且还得修改onClick里面的逻辑。那么比较好的方法是怎么样的呢?
定义一个数据发送器类:
/**
* 数据发送器Sender
*
* @author HansChen
*/
public interface Sender {
void sendData(byte[] data);
}
实现WiFi数据发送:
/**
* Sender的实现类,通过Wi-Fi发送数据
*
* @author HansChen
*/
public class WiFiSender implements Sender {
@Override
public void sendData(byte[] data) {
System.out.println("Send data by Wi-Fi");
}
}
实现蓝牙数据发送:
/**
* Sender的实现类,通过蓝牙发送数据
*
* @author HansChen
*/
public class BluetoothSender implements Sender {
@Override
public void sendData(byte[] data) {
System.out.println("Send data by Bluetooth");
}
}
这样,原来发送数据的地方就改为了:
private String mode; //Wi-Fi|Bluetooth
public void onClick() {
byte[] data = {0x00, 0x01};
Sender sender;
if ("Wi-Fi".equals(mode)) {
sender = new WiFiSender();
} else {
sender = new BluetoothSender();
}
sender.sendData(data);
}
有没有觉得代码优雅了一点?但是随着发送器Sender的实现类越来越多,每增加一个实现类,就需要在onClick里面实例化相应的实现类,能不能用一个单独的类来做这个创造实例的过程呢?这就是我们讲到的工厂。我们新增一个工厂类:
/**
* 简单工厂类
*
* @author HansChen
*/
public class SimpleFactory {
public static Sender createSender(String mode) {
switch (mode) {
case "Wi-Fi":
return new WiFiSender();
case "Bluetooth":
return new BluetoothSender();
default:
throw new IllegalArgumentException("illegal type: " + mode);
}
}
}
这样一来,怎么实例化数据发送器我们也不用管了,最终代码变为:
private String mode; //Wi-Fi|Bluetooth
public void onClick() {
byte[] data = {0x00, 0x01};
Sender sender = SimpleFactory.createSender(mode);
sender.sendData(data);
}
好了,到这里我们就完成了简单工厂模式的应用了,下图就是简单工厂模式的结构图:
工厂方法模式
简单工厂模式的优点在于工厂类包含了必要的判断逻辑,根据传入的参数动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。但是这里还是会有个问题,假设上面例子中新增了一个zigbee发送器,那么一定是需要修改简单工厂类的,也就是说,我们不但对扩展开放了,对修改也开放了,这是不好的。解决的方法是使用工厂方法模式,工厂方法模式是指定义一个用于创建对象的接口,让子类决定实例化哪一个类。下面还是通过代码来说明:
在简单工厂模式的基础上,让我们对工厂类也升级一下,首先定义一个工厂类接口:
public interface SenderFactory {
Sender createSender();
}
然后为每一个发送器的实现类各创建一个具体的工厂方法去实现这个接口
定义WiFiSender的工厂类:
public class WiFiSenderFactory implements SenderFactory {
@Override
public Sender createSender() {
return new WiFiSender();
}
}
定义BluetoothSender的工厂类:
public class BluetoothSenderFactory implements SenderFactory {
@Override
public Sender createSender() {
return new BluetoothSender();
}
}
这样,即使有新的Sender实现类加进来,我们只需要新增相应的工厂类就行了,不需要修改原有的工厂,下图就是工厂方法模式的结构图:
客户端调用代码:
private String mode; //Wi-Fi|Bluetooth
public void onClick() {
byte[] data = {0x00, 0x01};
SenderFactory factory;
if ("Wi-Fi".equals(mode)) {
factory = new WiFiSenderFactory();
} else {
factory = new BluetoothSenderFactory();
}
Sender sender = factory.createSender();
sender.sendData(data);
}
细心的读者可能已经发现了,工厂方法模式实现时,客户端需要决定实例化哪一个工厂类,相比于简单工厂模式,客户端多了一个选择判断的问题,也就是说,工厂方法模式把简单工厂模式的内部逻辑判断移到了客户端!你想要加功能,本来是修改简单工厂类的,现在改为修改客户端。但是这样带来的好处是整个工厂和产品体系都没有“修改”的变化,只有“扩展”的变化,完全符合了开放封闭原则。
总结
简单工厂模式和工厂方法模式都封装了对象的创建,它们使得高层策略模块在创建类的实例时无需依赖于这些类的具体实现。但是两种工厂模式之间又有差异:
- 简单工厂模式:最大的优点在于工厂类包含了必要的判断逻辑,根据客户端的条件动态地实例化相关的类。但这也是它的缺点,当扩展功能的时候,需要修改工厂方法,违反了开放封闭原则
- 工厂方法模式:符合开放封闭原则,但这带来的代价是扩展的时候要增加相应的工厂类,增加了开发量,而且需要修改客户端代码
设计模式之工厂模式(Factory)的更多相关文章
- 设计模式之工厂模式(Factory)
设计模式的工厂模式一共有三种:简单工厂模式,工厂模式,抽象工厂模式 简单工厂模式原理:只有一个工厂类,通过传参的形式确定所创建的产品对象种类 代码如下: #include <stdio.h> ...
- python 设计模式之工厂模式 Factory Pattern (简单工厂模式,工厂方法模式,抽象工厂模式)
十一回了趟老家,十一前工作一大堆忙成了狗,十一回来后又积累了一大堆又 忙成了狗,今天刚好抽了一点空开始写工厂方法模式 我看了<Head First 设计模式>P109--P133 这25页 ...
- 设计模式之工厂模式(Factory模式)
在面向对象系统设计中经常遇到以下两类问题: 1)为了提高内聚(Cohesion)和松耦合(Coupling),我们经常会抽象出一些类的公共接口以形成抽象基类或者接口.这样我们可以通过声明一个指向基类的 ...
- 设计模式~简单工厂模式(Factory)
简单工厂模式Simple Factory根据提供给它的数据,返回一个类的实例.通常它返回的类都有一个公共的父类(或者接口对象). 简单工厂的作用是实例化对象,而不需要客户了解这个对象属于哪个具体的子类 ...
- 【设计模式】工厂模式 Factory Pattern
1)简单工厂(不是模式) 简单工厂只是一种变成习惯,并非23种设计模式之一. 简单工厂提供将实例话那种类型留给运行时判断,而非编译时指定.简单工厂模式就是由一个工厂类根据传入的参数决定创建出哪一个类的 ...
- 设计模式之工厂模式 Factory实现
simpleFactory //car接口 public interface Car { void run(); } //两个实现类 public class Audi implements Car{ ...
- JAVA设计模式之工厂模式—Factory Pattern
1.工厂模式简介 工厂模式用于对象的创建,使得客户从具体的产品对象中被解耦. 2.工厂模式分类 这里以制造coffee的例子开始工厂模式设计之旅. 我们知道coffee只是一种泛举,在点购咖啡时需要指 ...
- java设计模式之 工厂模式Factory
好比某种套路,经过不断实践,证明对项目结构非常有利 如果需要获取某种对象,如同获取不同的产品 需要由工厂来提供,工厂模式 可能的类或者对象:工厂类 产品:Cat Dog Fish ... //动 ...
- 设计模式(一)工厂模式Factory(创建型)
设计模式一 工厂模式Factory 在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的.可是在一些情况下, new操作符直接生成对象会带来一些问题. ...
- 设计模式(一)工厂模式Factory(创建类型)
设计模式一 工厂模式Factory 在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的.可是在一些情况下, new操作符直接生成对象会带来一些问题. ...
随机推荐
- js循环和调用
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- ios发送短信验证码计时器的swift实现
转载自:http://www.jianshu.com/p/024dd2d6e6e6# Update: Xcode 8.2.1 Swift 3 先介绍一下 属性观测器(Property Observer ...
- vue项目如何在node启动
首先将vue项目通过命令npm run build 打包,然后创建start.js,代码如下: // const userApi = require('./api'); const fs = requ ...
- Spring AOP 知识整理
通过一个多月的 Spring AOP 的学习,掌握了 Spring AOP 的基本概念.AOP 是面向切面的编程(Aspect-Oriented Programming),是基于 OOP(面向对象的编 ...
- Exceptionless—本地部署
参考:https://blog.csdn.net/shiyaru1314/article/details/76176236 自己采坑: ES 1.7.5版本不好使.使用最新版本6.X以上版本也不行 用 ...
- Java 中文数字转换为阿拉伯数字
贴出代码,方便学习交流,稍后放出镜像问题的代码 package com.thunisoft.cail.utils; import com.sun.istack.internal.NotNull; im ...
- oop面向对象知识总结 静态成员和友元
第十一章 静态成员和友元 11.1 静态成员 1.C++类当中的静态数据成员仍借用保留字static,但是与之前的静态全局变量,静态局部变量以及静态函数没有关系. 2.静态数据成员不占用具体对象的数据 ...
- 基于Rancher搭建Kubernetes
基于Rancher搭建Kubernetes可以大大的简化安装的步骤,直接安装Kubernetes操作复杂并且容易出错. 转自 https://blog.csdn.net/u011142688/arti ...
- CSS(4)---三大特性(继承性,层叠性,优先级)
CSS(4)---三大特性(继承性,层叠性,优先级) CSS有三大特性分别是: 继承性,层叠性,优先级. 一.继承性 概念 给父元素设置一些属性,子元素也可以使用,这个我们就称之为继承性. 注意 1. ...
- RHEL7-Vsftpd匿名用户
实现:匿名用户创建目录,可以上传.下载文件,但是不可删除文件,禁止本地用户登陆. Vsftpd.conf部分参数 第一步:虚拟机挂载镜像 略 第二步:执行挂载命令 略 第三步:编写yum仓库文件 略 ...