在一次面试中了解到工厂模式在实际应用中的重要性,可以说工厂模式的应用随处可见,以下是百度百科对工厂模式的介绍

工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性尽量少的修改量

在看了几篇写工厂模式的文章后,看见一篇我认为比较容易理解的代码说明:

一.简单(静态)工厂模式

1,首先建立一个产品的抽象类

需要生产什么产品(实例对象)就需要首先建立一个相应产品的抽象类

  1. public abstract class INoodles {
  2. /**
  3. * 描述每种面条啥样的
  4. */
  5. public abstract void desc();
  6. }

2.再建立几种具体的产品类如:

这里建立了三个产品类:兰州拉面,泡面,干扣面(没吃过)

  1. public class LzNoodles extends INoodles {
  2. @Override
  3. public void desc() {
  4. System.out.println("兰州拉面");
  5. }
  6. }
  1. public class PaoNoodles extends INoodles {
  2. @Override
  3. public void desc() {
  4. System.out.println("泡面");
  5. }
  6. }
  1. public class GankouNoodles extends INoodles {
  2. @Override
  3. public void desc() {
  4. System.out.println("干扣面");
  5. }
  6. }

3.在建立完这些产品后就可以建立(造面的)工厂了:

工厂里面包含了我们可以生产的产品(面)

  1. public class SimpleNoodlesFactory {
  2. public static final int TYPE_LZ = 1;//兰州拉面
  3. public static final int TYPE_PM = 2;//泡面
  4. public static final int TYPE_GK = 3;//干扣面
  5. public static INoodles createNoodles(int type) {
  6. switch (type) {
  7. case TYPE_LZ:
  8. return new LzNoodles();
  9. case TYPE_PM:
  10. return new PaoNoodles();
  11. case TYPE_GK:
  12. default:
  13. return new GankouNoodles();
  14. }
  15. }
  16. }

4.开始根据客人的要求生产产品

如下代码是生产干扣面(真心不知道这名字是怎么来的)的过程。

  1. INoodles noodles = SimpleNoodlesFactory.createNoodles(SimpleNoodlesFactory.TYPE_GK);
  2. noodles.desc();

该设计模式只可以生产工厂能生产的产品,如需要增加产品,需要在工厂类中增加相应的静态变量。

特点

1 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。

2 create()方法通常是静态的,所以也称之为静态工厂

缺点

1 扩展性差(我想增加一种面条,除了新增一个面条产品类,还需要修改工厂类方法)

2 不同的产品需要不同额外参数的时候 不支持。

二、另一种简单工厂(反射):

利用反射Class.forName(clz.getName()).newInstance()实现的简单工厂:

  1. public class StaticNoodlesFactory {
  2. /**
  3. * 传入Class实例化面条产品类
  4. *
  5. * @param clz
  6. * @param <T>
  7. * @return
  8. */
  9. public static <T extends INoodles> T createNoodles(Class<T> clz) {
  10. T result = null;
  11. try {
  12. result = (T) Class.forName(clz.getName()).newInstance();
  13. } catch (Exception e) {
  14. e.printStackTrace();
  15. }
  16. return result;
  17. }
  18. }

特点

1 它也是一个具体的类,非接口 抽象类。但它的create()方法,是利用反射机制生成对象返回,好处是增加一种产品时,不需要修改create()的代码

缺点

这种写法粗看牛逼,细想之下,不谈reflection的效率还有以下问题:

1 个人觉得不好,因为Class.forName(clz.getName()).newInstance()调用的是无参构造函数生成对象,它和new Object()是一样的性质,而工厂方法应该用于复杂对象的初始化 ,当需要调用有参的构造函数时便无能为力了,这样像为了工厂而工厂。

2 不同的产品需要不同额外参数的时候 不支持

三、 多方法工厂(常用)

使用方法二 三实现的工厂,都有一个缺点:不同的产品需要不同额外参数的时候 不支持。

而且如果使用时传递的type、Class出错,将不能得到正确的对象,容错率不高。

而多方法的工厂模式为不同产品,提供不同的生产方法,使用时 需要哪种产品就调用该种产品的方法,使用方便、容错率高

工厂如下:

  1. public class MulWayNoodlesFactory {
  2. /**
  3. * 模仿Executors 类
  4. * 生产泡面
  5. *
  6. * @return
  7. */
  8. public static INoodles createPm() {
  9. return new PaoNoodles();
  10. }
  11. /**
  12. * 模仿Executors 类
  13. * 生产兰州拉面
  14. *
  15. * @return
  16. */
  17. public static INoodles createLz() {
  18. return new LzNoodles();
  19. }
  20. /**
  21. * 模仿Executors 类
  22. * 生产干扣面
  23. *
  24. * @return
  25. */
  26. public static INoodles createGk() {
  27. return new GankouNoodles();
  28. }
  29. }
  1. 这种我比较青睐,增加一个新面条,只要去增加一个static方法即可,也不修改原方法逻辑

查看java源码:java.util.concurrent.Executors类便是一个生成Executor 的工厂 ,其采用的便是 多方法静态工厂模式

例如ThreadPoolExecutor类构造方法有5个参数,其中三个参数写法固定,前两个参数可配置,如下写。

  1. public static ExecutorService newFixedThreadPool(int nThreads) {
  2. return new ThreadPoolExecutor(nThreads, nThreads,
  3. 0L, TimeUnit.MILLISECONDS,
  4. new LinkedBlockingQueue<Runnable>());
  5. }

又如JDK想增加创建ForkJoinPool类的方法了,只想配置parallelism参数,便在类里增加一个如下的方法:

  1. public static ExecutorService newWorkStealingPool(int parallelism) {
  2. return new ForkJoinPool
  3. (parallelism,
  4. ForkJoinPool.defaultForkJoinWorkerThreadFactory,
  5. null, true);
  6. }

这个例子可以感受到工厂方法的魅力了吧:方便创建 同种类型的 复杂参数 对象

四 普通工厂

普通工厂就是把简单工厂中具体的工厂类,划分成两层:抽象工厂层+具体的工厂子类层。(一般->特殊)

面条工厂(抽象工厂类),作用就是生产面条:

  1. public abstract class NoodlesFactory {
  2. public abstract INoodles create();
  3. }

兰州拉面工厂 (具体工厂子类):

  1. public class LzFactory extends NoodlesFactory {
  2. @Override
  3. public INoodles create() {
  4. return new LzNoodles();
  5. }
  6. }

泡面工厂 (具体工厂子类):

  1. public class PaoFactory extends NoodlesFactory {
  2. @Override
  3. public INoodles create() {
  4. return new PaoNoodles();
  5. }
  6. }

最爱的干扣面工厂 (具体工厂子类):

  1. public class GankouFactory extends NoodlesFactory {
  2. @Override
  3. public INoodles create() {
  4. return new GankouNoodles();
  5. }
  6. }

使用时:

  1. /**
  2. * 普通工厂方法:
  3. */
  4. System.out.println("===========================普通工厂方法==============================" +
  5. "\n 这种要多写一个类,不过更面向对象");
  6. NoodlesFactory factory1 = new GankouFactory();
  7. INoodles gk3 = factory1.create();
  8. gk3.desc();

普通工厂与简单工厂模式的区别:

可以看出,普通工厂模式特点:不仅仅做出来的产品要抽象, 工厂也应该需要抽象

工厂方法使一个产品类的实例化延迟到其具体工厂子类.

工厂方法的好处就是更拥抱变化。当需求变化,只需要增删相应的类,不需要修改已有的类

而简单工厂需要修改工厂类的create()方法,多方法静态工厂模式需要增加一个静态方法。

六 抽象工厂:

以上介绍的工厂都是单产品系的。抽象工厂是多产品系 (貌似也有产品家族的说法)。

举个例子来说,每个店(工厂)不仅仅卖面条,还提供饮料卖。
提供饮料卖,饮料是产品,先抽象一个产品类,饮料:

  1. public abstract class IDrinks {
  2. /**
  3. * 描述每种饮料多少钱
  4. */
  5. public abstract void prices();
  6. }

然后实现两个具体产品类:
可乐:

  1. public class ColaDrinks extends IDrinks {
  2. @Override
  3. public void prices() {
  4. System.out.println("可乐三块五");
  5. }
  6. }

屌丝还是多喝水吧:

  1. public class WaterDrinks extends IDrinks {
  2. @Override
  3. public void prices() {
  4. System.out.println("和我一样的穷鬼都喝水,不要钱~!");
  5. }
  6. }

抽象饭店,无外乎吃喝(抽象工厂类):

  1. public abstract class AbstractFoodFactory {
  2. /**
  3. * 生产面条
  4. *
  5. * @return
  6. */
  7. public abstract INoodles createNoodles();
  8. /**
  9. * 生产饮料
  10. */
  11. public abstract IDrinks createDrinks();
  12. }

兰州大酒店(具体工厂类):

  1. public class LzlmFoodFactory extends AbstractFoodFactory {
  2. @Override
  3. public INoodles createNoodles() {
  4. return new LzNoodles();//卖兰州拉面
  5. }
  6. @Override
  7. public IDrinks createDrinks() {
  8. return new WaterDrinks();//卖水
  9. }
  10. }

KFC(具体工厂类):

  1. public class KFCFoodFactory extends AbstractFoodFactory {
  2. @Override
  3. public INoodles createNoodles() {
  4. return new PaoNoodles();//KFC居然卖泡面
  5. }
  6. @Override
  7. public IDrinks createDrinks() {
  8. return new ColaDrinks();//卖可乐
  9. }
  10. }

使用:

  1. /**
  2. * 抽象工厂方法:
  3. */
  4. System.out.println("==============================抽象方法==============================" )
  5. AbstractFoodFactory abstractFoodFactory1 = new KFCFoodFactory();
  6. abstractFoodFactory1.createDrinks().prices();
  7. abstractFoodFactory1.createNoodles().desc();
  8. abstractFoodFactory1= new LzlmFoodFactory();
  9. abstractFoodFactory1.createDrinks().prices();
  10. abstractFoodFactory1.createNoodles().desc();

输出:

  1. ==============================抽象方法==============================
  2. 可乐三块五
  3. 泡面
  4. 和我一样的穷鬼都喝水,不要钱~!
  5. 兰州拉面

小结:

将工厂也抽象了,在使用时,工厂和产品都是面向接口编程,OO(面向对象)的不得了。

六 个人总结和使用场景

一句话总结工厂模式:方便创建 同种产品类型的 复杂参数 对象

工厂模式重点就是适用于 构建同产品类型(同一个接口 基类)的不同对象时,这些对象new很复杂,需要很多的参数,而这些参数中大部分都是固定的,so,懒惰的程序员便用工厂模式封装之。
(如果构建某个对象很复杂,需要很多参数,但这些参数大部分都是“不固定”的,应该使用Builder模式)

为了适应程序的扩展性,拥抱变化,便衍生出了 普通工厂、抽象工厂等模式。

本文参考的文章的作者更偏向于使用多方法工厂,但我认为普通工厂和抽象工厂使用范围更广,而且更好理解。

学习参考

https://blog.csdn.net/zxt0601/article/details/52798423

java面试题----工厂模式大整理(面试问的较多)的更多相关文章

  1. Java设计模式之工厂模式(Factory模式)介绍(转载)

    原文见:http://www.jb51.net/article/62068.htm 这篇文章主要介绍了Java设计模式之工厂模式(Factory模式)介绍,本文讲解了为何使用工厂模式.工厂方法.抽象工 ...

  2. java反射机制(工厂模式)

    http://www.phpddt.com/dhtml/338.html java里面没有typeof,js有. 我终于实现了用反射机制编写的工厂模式.java反射在工厂模式可以体现. 包含产品接口类 ...

  3. 浅析JAVA设计模式之工厂模式(一)

    1 工厂模式简单介绍 工厂模式的定义:简单地说,用来实例化对象,取代new操作. 工厂模式专门负责将大量有共同接口的类实例化.工作模式能够动态决定将哪一个类实例化.不用先知道每次要实例化哪一个类. 工 ...

  4. Java 设计模式之工厂模式(二)

    原文地址:Java 设计模式之工厂模式(二) 博客地址:http://www.extlight.com 一.背景 本篇内容是 Java 设计模式创建型模式的第二篇.上一篇主题为 <Java 设计 ...

  5. 浅析JAVA设计模式之工厂模式(二)

    1 工厂方法模式简单介绍 工厂方法 (Factroy Method)模式:又称多态性工厂模式(Polymorphic Factory),在这样的模式中,核心工厂不再是一个详细的类.而是一个抽象工厂,提 ...

  6. java设计模式2————工厂模式

    1.工厂模式介绍: 1.1.实现了创建者与调用者的分离 1.2.详细分类: 简单工厂模式 工厂方法模式 抽象工厂模式 1.3.所遵循的OOP原则: 开闭原则:对扩展开放,对修改关闭 依赖倒转原则:面向 ...

  7. 百度搜索 “Java面试题” 前200页(面试必看)

    前言 本文中的题目来源于网上的一篇文章<百度搜索 "Java面试题" 前200页>,但该文章里面只有题目,没有答案.因此,我整理了一些答案发布于本文.本文整理答案的原则 ...

  8. Java设计模式之工厂模式(Factory)

    前言: 前面学习了建造者设计模式,接下来学习一下Retrofit中使用的另外一个设计模式,工厂设计模式!!!里面采用工厂模式使得数据转换得到完全解耦,工厂模式的好处用到了极致,如此好的设计模式我们怎能 ...

  9. Java设计模式之-----工厂模式(简单工厂,抽象工厂)

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

随机推荐

  1. Celery 大量任务 分发

    Celery是由Python开发的一个简单.灵活.可靠的处理大量任务的分发系统,它不仅支持实时处理也支持任务调度. user:用户程序,用于告知celery去执行一个任务. broker: 存放任务( ...

  2. 116th LeetCode Weekly Contest N-Repeated Element in Size 2N Array

    In a array A of size 2N, there are N+1 unique elements, and exactly one of these elements is repeate ...

  3. ZOJ - 2401 水DP

    最近会多做点巩固基础的题目 #include<iostream> #include<algorithm> #include<cstdio> #include< ...

  4. dedecmd 全局标签

    dedecms全局标签     dedecms 标签使用手册  全局标签   adminname|责任编辑   arclist|文档列表   arclistsg|独立单表模型列表   ask|问答标签 ...

  5. [转] JavaScript控制浏览器全屏及各种浏览器全屏模式的方法、属性和事件

    [From] http://www.jb51.net/article/76695.htm HTML 5中的full screen,目前可以在除IE和opera外的浏览器中使用 ,有的时候用来做全屏AP ...

  6. 搭建Redis报错

    2018-10-26 报错信息 You need tcl 8.5 or newer in order to run the Redis test 原因 缺少 tcl 插件 解决方式 wget http ...

  7. VUE 入门教程

    http://www.runoob.com/w3cnote/vue-js-quickstart.html VUE安装教程 https://segmentfault.com/a/119000001218 ...

  8. jmeter发送邮件的模板

    <hr/> (本邮件是程序自动下发的,请勿回复!)<br/><hr/> 项目名称:$PROJECT_NAME<br/><hr/> 构建编号: ...

  9. PIE SDK面元素的绘制

    1. 功能简介 在数据的处理中会用到线元素的绘制,目前PIE SDK支持IFillSymbol接口,FillSymbol对象是用于修饰填充面状对象的符号,它包括MarkerFillSymbol(由点状 ...

  10. Mac下Jenkins+SVN+Xcode构建持续导出环境

    1 安装Jenkins Jenkins是基于Java开发的一种持续集成工具.所以呢,要使用Jenkins必须使用先安装JDK. JDK安装 JDK 下载地址 jdk 1.8.png 安装JDK的过程略 ...