问题提出

Java的工厂模式与现实生活中的工厂的模型是很相似的。工厂是用来做什么?当然是用来生成产品。因此在Java的工厂模式的关键点就是如何描述好产品和工厂这2个角色之间的关系。

下面来仔细描述一下不同的关系以及对应的设计模式

1)单一产品系,工厂只生产一种类型的产品

让我们简单构思一下简单的工厂生产模型,既然只有一个产品,那只需要一个车间就好了,一个车间分别生产三种不同种类的小汽车。好,下面看看简单工厂的设计模式。

//定义小汽车接口:ICar.java
public interface ICar {
}
public class TopCar implements ICar {
}
public class MidCar implements ICar {
}
public class LowCar implements ICar {
}
public class CarSimpleFactory {
public static final String TOPTYPE = "toptype";
public static final String MIDTYPE = "midtype";
public static final String LOWTYPE = "lowtype"; private CarSimpleFactory(){ }
public static ICar create(String mark){
ICar obj = null;
if(mark.equals(TOPTYPE)){
obj = new TopCar();
}
else if(mark.equals(MIDTYPE)){
obj = new MidCar();
}
else if(mark.equals(LOWTYPE)){
obj = new LowCar();
}
return obj;
}
}

简单工厂功能类编写步骤:

1.编写抽象产品接口

2.编写具体产品子类

3.编写工厂类。简单工厂类的特点,它是一个具体的类,非接口型抽象类。有一个重要的create()方法,并且用if...else或者switch开发创建所需产品。因为可以把这个简单工厂类实现成一个工具类,所以直接用静态方法就可以了,如有必要甚至可以把构造方法私有化。

下面考虑一种情形,工厂扩张啦!可以加工生产超级高档型的汽车。在上面的生产模式下要怎么修改呢?

1)新增ICar子类SuperCar

2)修改工厂类SimpleCarFactory中的create()方法,添加判断分支。

子类SuperCar的添加是必然的,然而能不能不用修改工厂类呢?

或者从另一个角度分析,在一个生产线上生产几种不同种类的产品,这样我们还需要对每个产品加以判断种类来分类。当然,假若只有2种种类要区分,这样当然没问题,但是若是有多个种类要区分呢?显然,不能在一条生产线上生产多种种类的产品!那意味着对于每一种种类我们都需要一条生产线。这就是所谓的工厂模式!

public abstract class AbstractFactory {
public abstract ICar create();
}
public class LowFactory extends AbstractFactory {
public ICar create(){
return new LowCar();
}
}
public class MidFactory extends AbstractFactory {
public ICar create(){
return new MidCar();
}
}
public class TopFactory extends AbstractFactory {
public ICar create(){
return new TopCar();
}
}

而观察代码,只要有ICar.java,AbstractFactory.java这两个文件,其他具体产品类,工厂类源文件没有,编译也能通过。

对于AbstractFactory,可以定义为抽象类,也可以定义为接口。这里的create()是抽象方法,没参数,表明在具体的子类工厂中创建某个具体产品。

工厂方法的主要特征是:当需求分析发生变化是,只需要增加和删除相应的类,而不是修改已有的类。例如添加超高档的小汽车,只需要增加SuperCar以及SuperFactory两个类即可。所以工厂方法更易于软件的二次开发以及维护。

当然啦,一个工厂很有可能不止生成一种产品。下面看看多产品系。

2)多产品系,特征相同

UML图与工厂模式基本没什么区别,这里就不再画了。

一般来说,简单工厂和工厂模式都是单产品系的,而对于上面这种架构,称之为抽象工厂。但从本质上来说,抽象工厂和工厂模式是统一的。这里就不再述说。

3)多产品系,部分特征相同

public abstract class AbstractFactory {
/**
* 多产品系,小汽车和公共汽车都有高,中档类型,小汽车有低档类型,而公共汽车没有
*/
}
public abstract class AbstractFactory1 extends AbstractFactory {
public abstract ICar createCar(); //产生小汽车对象
public abstract IBus createBus(); //产生公共汽车对象
}
public abstract class AbstractFactory2 extends AbstractFactory {
public abstract ICar createCar(); //产生小汽车对象
}

这里着重看看AbstractFactory,AbstractFactory1,AbstractFactory2.

1)具有相同特征的小汽车和公共汽车放在相同的工厂里面

2)该类也是抽象类,表明“特征是多个”。这里特征表示“高中低档”。

工厂模式大概就讲到这里,看到这里,相信很多人都有一种,工厂模式原来也不过如此。但是,个人觉得无论什么设计模式,看上去都似乎很好理解很容易。但是,当遇到问题需要自己分析设计的时候,就顿时没了头绪。

原因大概有2个,一是对这种设计模式还并不是十分熟悉和理解,二当然就是没有实践过。闲话不多说,下面让我们操刀实践一波。

例子:编写读文件功能。读取文本文件,包括GBK,UTF-8.编码下的文本文件,要求获得全文内容;读取图像文件,包括BMP,GIF,JPG文件,要求获得图像宽度,长度,每一点的三基色信息。

代码如下:

读取文本文件方法需要两个参数:文件名和编码方式;而读取图像文件需要一个参数:文件名。而根据题意,两种读取文件返回值类型有所差异。

如何用接口屏蔽方法参数个数,返回值类型的差异,是定义接口的关键。

public interface IRead<T> {
//如何用接口屏蔽方法参数个数,返回值类型的差异,这是定义接口的关键
T read(String ... in);
}
package factoryModel.explorer2;

import java.io.File;
import java.io.FileInputStream; /**
* Created by lenovo on 2017/4/17.
*/
public class TextRead implements IRead<String> { //读文本文件
public String read(String ... in){ //可输入0或者多个参数
String result = null; //result是结果串
try{
File file = new File(in[0]); //in[0]代表文件名
long len = file.length();
FileInputStream input = new FileInputStream(in[0]);
byte buf[] = new byte[(int)len];
input.read(buf);
result = new String(buf,in[1]); //按照in[1]编码方式转化为可见字符串
input.close();
}
catch (Exception ex){
System.out.println(ex.getMessage());
}
return result;
}
}
package factoryModel.explorer2;

/**
* Created by lenovo on 2017/4/17.
*/
public class ImageInfo {
private int width; //图像宽度
private int height; //图像高度
private int r[][]; //红色分量
private int g[][]; //绿色分量
private int b[][]; //蓝色分量 public int getWidth() {
return width;
} public void setWidth(int width) {
this.width = width;
} public int getHeight() {
return height;
} public void setHeight(int height) {
this.height = height;
} public int[][] getR() {
return r;
} public int[][] getG() {
return g;
} public int[][] getB() {
return b;
} public void setRGB(int rgb[]){
r = new int [height][width];
g = new int [height][width];
b = new int [height][width];
int pos = 0;
for(int i=0;i<height;i++){
pos = width*i;
for(int j=0;j<width;j++){
r[i][j] = (rgb[pos+j]&0xff0000)>>16;
g[i][j] = (rgb[pos+j]&0x00ff00)>>8;
b[i][j] = (rgb[pos+j]&0x0000ff);
}
}
} }
package factoryModel.explorer2;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException; /**
* Created by lenovo on 2017/4/17.
*/
public class ImageRead implements IRead<ImageInfo> {
public ImageInfo read(String... in){
BufferedImage bi = null;
File f = new File(in[0]);
try{
bi = ImageIO.read(f);
}
catch (IOException ex){
ex.printStackTrace();
}
int width = bi.getWidth();
int height = bi.getHeight();
int rgb[] = new int[width*height]; bi.getRGB(0,0,width,height,rgb,width,height); //将图像数据读到result缓存区
ImageInfo imageInfo = new ImageInfo();
imageInfo.setHeight(height);
imageInfo.setWidth(width);
return imageInfo;
}
}
public abstract class AbstractFactory {
  //定义抽象工厂
public abstract IRead create();
}
public class TextFactory extends AbstractFactory {
public IRead create(){
return new TextRead();
}
}
public class ImageFactory extends AbstractFactory {
public IRead create(){
return new ImageRead();
}
}

对于上面抽象工厂类其实并不够完善,如何选择具体工厂类没有体现。解决方法有两种。一是像简单工厂那样添加选择分支。二是使用反射。

下面的代码是使用了反射技术

public abstract class AbstractFactory {
public abstract IRead create();
static AbstractFactory create(String className){
AbstractFactory factory = null;
try{
Class c = Class.forName(className);
factory = (AbstractFactory)c.newInstance();
}
catch (Exception ex){
ex.printStackTrace();
}
return factory;
}
}

运用反射技术,实现了更加灵活的自动工厂选择功能。当添加新具体工厂类的时候,不需要修改AbstractFactory类。

Java设计模式:工厂模式的更多相关文章

  1. 【设计模式】Java设计模式 -工厂模式

    [设计模式]Java设计模式 -工厂模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德 分享学习心得,欢迎指正,大家一起学习成长! 目 ...

  2. 一张图搞定Java设计模式——工厂模式! 就问你要不要学!

    小编今天分享的内容是Java设计模式之工厂模式. 收藏之前,务必点个赞,这对小编能否在头条继续给大家分享Java的知识很重要,谢谢!文末有投票,你想了解Java的哪一部分内容,请反馈给我. 获取学习资 ...

  3. 10.Java设计模式 工厂模式,单例模式

    Java 之工厂方法和抽象工厂模式 1. 概念 工厂方法:一抽象产品类派生出多个具体产品类:一抽象工厂类派生出多个具体工厂类:每个具体工厂类只能创建一个具体产品类的实例. 即定义一个创建对象的接口(即 ...

  4. 学习:java设计模式—工厂模式

    一.工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式在<Java与模式>中分为三类: 1)简单工厂模式(Simple Facto ...

  5. Java设计模式---工厂模式(简单工厂、工厂方法、抽象工厂)

    工厂模式:主要用来实例化有共同接口的类,工厂模式可以动态决定应该实例化那一个类.工厂模式的形态工厂模式主要用一下几种形态:1:简单工厂(Simple Factory).2:工厂方法(Factory M ...

  6. java设计模式-工厂模式(springweb为例子)

    一般而言,工厂模式分为3种,简单工厂模式,工厂方法模式,抽象工厂模式.这三种工厂模式逐层深入吧. 一,从springWeb.jar包使用抽象工厂模式的一个例子聊起 之前对spring各种痴迷,所以在需 ...

  7. java设计模式—工厂模式

    一.工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式在<Java与模式>中分为三类:1)简单工厂模式(Simple Factor ...

  8. Java设计模式——工厂模式

    一.工厂模式分类 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式在<Java与模式>中分为三类: (1)简单工厂模式(Simp ...

  9. Java设计模式の工厂模式

    -------------------------------------------------------- 目录:  一.序言 二.简单工厂模式 三.工厂方法模式 四.简单工厂和工厂方法模式的比 ...

  10. 1.Java设计模式-工厂模式

    1.简单工厂模式(Factory Method) 常用的工厂模式是静态工厂模式,利用static修饰方法,作为一种类似于常见的工具类Utils等辅助效果,一般情况下工厂类不需要实例化. //1.定义一 ...

随机推荐

  1. Java表达式中的那些坑

    [1]您确定真正了解后缀表达式与前缀表达式的区别吗? public class IncrementDemo{ public static void main(String[] args) { int ...

  2. 编程那些事儿:如何快速地"借用"CSS

    做前端开发有时候会碰到任务紧急,需要马上写好静态页的问题.比如,设计师给你扔了一个设计稿,要你在下班之前搞定.这时候你如热锅上的蚂蚁,如果自己写css的话,时间紧张,于是上网找了一下相关模板页面,找到 ...

  3. jQuery的ajax详解

    很多朋友都喜欢用JQ 而ajax更是JQ里必不可少的 下面为大家详细介绍一下JQ的ajax 首先 什么是ajax: AJAX = 异步 JavaScript 和 XML(Asynchronous Ja ...

  4. 如何理解jQuery中的ajaxSubmit方法

    版权声明:本文为博主原创文章,转载请标注:www.cnblogs.com/gdsblog 刚刚学习中,使用到了ajaxSubmit,犹豫以前没有接触㢧这个,所以刚开始是一脸懵逼状态,最后通过查找资料的 ...

  5. wemall开源商城免费商城系统部分代码(内含代码地址)

    wemall开源商城免费商城系统部分代码,下面分享部分代码,供学习者学习: 开源版把install文件夹下的install.lock删除之后可进行自动安装 后台访问地址:http:// www.xxx ...

  6. 3410: [Usaco2009 Dec]Selfish Grazing 自私的食草者

    3410: [Usaco2009 Dec]Selfish Grazing 自私的食草者 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 71  Solve ...

  7. Action的创建和配置

    计应134(实验班) 李佳鸿 Action类—Struts组件 在RequestProcessor类预处理请求时,在创建了Action的实例后,就调用自身的processActionPerform() ...

  8. 解决WebStorm无法连接到Chrome

    问题: 点击 中的chrome时,出现了错误,如下: 解决办法: 找到 File>setting>Web Browser 修改为 C:\Program Files (x86)\Google ...

  9. Metadata Service 一个最简单的应用 - 每天5分钟玩转 OpenStack(164)

    实现 instance 定制化,cloud-init(或 cloudbase-init)只是故事的一半,metadata service 则是故事的的另一半.两者的分工是:metadata servi ...

  10. TFS2017代码搜索功能

    当团队或者公司的研发中心的代码库扩展到了一定程度,在代码库中查找一些需要的代码会变的比较困难.比如敏捷模式下的项目小组希望能够找到并重用其他小组开发的一些基础性的功能代码,我们通常需要去找当事人去询问 ...