java面试题----工厂模式大整理(面试问的较多),大厂Java面试题笔试
写在最前面,我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家。扫码加微信好友进【程序员面试学习交流群】,免费领取。也欢迎各位一起在群里探讨技术。
在一次面试中了解到工厂模式在实际应用中的重要性,可以说工厂模式的应用随处可见,以下是百度百科对工厂模式的介绍
工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。
在看了几篇写工厂模式的文章后,看见一篇我认为比较容易理解的代码说明:
一.简单(静态)工厂模式
1,首先建立一个产品的抽象类
需要生产什么产品(实例对象)就需要首先建立一个相应产品的抽象类
[code]public abstract class INoodles { /** * 描述每种面条啥样的 */ public abstract void desc(); }
2.再建立几种具体的产品类如:
这里建立了三个产品类:兰州拉面,泡面,干扣面(没吃过)
[code]public class LzNoodles extends INoodles { @Override public void desc() { System.out.println("兰州拉面"); } }
[code]public class PaoNoodles extends INoodles { @Override public void desc() { System.out.println("泡面"); } }
[code]public class GankouNoodles extends INoodles { @Override public void desc() { System.out.println("干扣面"); } }
3.在建立完这些产品后就可以建立(造面的)工厂了:
工厂里面包含了我们可以生产的产品(面)
[code]public class SimpleNoodlesFactory { public static final int TYPE_LZ = 1;//兰州拉面 public static final int TYPE_PM = 2;//泡面 public static final int TYPE_GK = 3;//干扣面 public static INoodles createNoodles(int type) { switch (type) { case TYPE_LZ: return new LzNoodles(); case TYPE_PM: return new PaoNoodles(); case TYPE_GK: default: return new GankouNoodles(); } } }
4.开始根据客人的要求生产产品
如下代码是生产干扣面(真心不知道这名字是怎么来的)的过程。
[code]INoodles noodles = SimpleNoodlesFactory.createNoodles(SimpleNoodlesFactory.TYPE_GK); noodles.desc();
该设计模式只可以生产工厂能生产的产品,如需要增加产品,需要在工厂类中增加相应的静态变量。
特点
1 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
2 create()方法通常是静态的,所以也称之为静态工厂。
缺点
1 扩展性差(我想增加一种面条,除了新增一个面条产品类,还需要修改工厂类方法)
2 不同的产品需要不同额外参数的时候 不支持。
二、另一种简单工厂(反射):
利用反射
Class.forName(clz.getName()).newInstance()实现的简单工厂:
[code]public class StaticNoodlesFactory { /** * 传入Class实例化面条产品类 * * @param clz * @param <T> * @return */ public static <T extends INoodles> T createNoodles(Class<T> clz) { T result = null; try { result = (T) Class.forName(clz.getName()).newInstance(); } catch (Exception e) { e.printStackTrace(); } return result; } }
特点
1 它也是一个具体的类,非接口 抽象类。但它的create()方法,是利用反射机制生成对象返回,好处是增加一种产品时,不需要修改create()的代码。
缺点
这种写法粗看牛逼,细想之下,不谈reflection的效率还有以下问题:
1 个人觉得不好,因为Class.forName(clz.getName()).newInstance()调用的是无参构造函数生成对象,它和new Object()是一样的性质,而工厂方法应该用于复杂对象的初始化 ,当需要调用有参的构造函数时便无能为力了,这样像为了工厂而工厂。
2 不同的产品需要不同额外参数的时候 不支持
三、 多方法工厂(常用)
使用方法二 三实现的工厂,都有一个缺点:不同的产品需要不同额外参数的时候 不支持。
而且如果使用时传递的type、Class出错,将不能得到正确的对象,容错率不高。
而多方法的工厂模式为不同产品,提供不同的生产方法,使用时 需要哪种产品就调用该种产品的方法,使用方便、容错率高。
工厂如下:
[code]public class MulWayNoodlesFactory { /** * 模仿Executors 类 * 生产泡面 * * @return */ public static INoodles createPm() { return new PaoNoodles(); } /** * 模仿Executors 类 * 生产兰州拉面 * * @return */ public static INoodles createLz() { return new LzNoodles(); } /** * 模仿Executors 类 * 生产干扣面 * * @return */ public static INoodles createGk() { return new GankouNoodles(); } }
[code]这种我比较青睐,增加一个新面条,只要去增加一个static方法即可,也不修改原方法逻辑
查看java源码:
java.util.concurrent.Executors类便是一个生成
Executor的工厂 ,其采用的便是 多方法静态工厂模式:
例如
ThreadPoolExecutor类构造方法有5个参数,其中三个参数写法固定,前两个参数可配置,如下写。
[code] public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
又如JDK想增加创建
ForkJoinPool类的方法了,只想配置
parallelism参数,便在类里增加一个如下的方法:
[code] public static ExecutorService newWorkStealingPool(int parallelism) { return new ForkJoinPool (parallelism, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); }
这个例子可以感受到工厂方法的魅力了吧:方便创建 同种类型的 复杂参数 对象。
四 普通工厂
普通工厂就是把简单工厂中具体的工厂类,划分成两层:抽象工厂层+具体的工厂子类层。(一般->特殊)
面条工厂(抽象工厂类),作用就是生产面条:
[code]public abstract class NoodlesFactory { public abstract INoodles create(); }
兰州拉面工厂 (具体工厂子类):
[code]public class LzFactory extends NoodlesFactory { @Override public INoodles create() { return new LzNoodles(); } }
泡面工厂 (具体工厂子类):
[code]public class PaoFactory extends NoodlesFactory { @Override public INoodles create() { return new PaoNoodles(); } }
最爱的干扣面工厂 (具体工厂子类):
[code]public class GankouFactory extends NoodlesFactory { @Override public INoodles create() { return new GankouNoodles(); } }
使用时:
[code] /** * 普通工厂方法: */ System.out.println("===========================普通工厂方法==============================" + " 这种要多写一个类,不过更面向对象"); NoodlesFactory factory1 = new GankouFactory(); INoodles gk3 = factory1.create(); gk3.desc();
普通工厂与简单工厂模式的区别:
可以看出,普通工厂模式特点:不仅仅做出来的产品要抽象, 工厂也应该需要抽象。
工厂方法使一个产品类的实例化延迟到其具体工厂子类.
工厂方法的好处就是更拥抱变化。当需求变化,只需要增删相应的类,不需要修改已有的类。
而简单工厂需要修改工厂类的create()方法,多方法静态工厂模式需要增加一个静态方法。
六 抽象工厂:
以上介绍的工厂都是单产品系的。抽象工厂是多产品系 (貌似也有产品家族的说法)。
举个例子来说,每个店(工厂)不仅仅卖面条,还提供饮料卖。
提供饮料卖,饮料是产品,先抽象一个产品类,饮料:
[code]public abstract class IDrinks { /** * 描述每种饮料多少钱 */ public abstract void prices(); }
然后实现两个具体产品类:
可乐:
[code]public class ColaDrinks extends IDrinks { @Override public void prices() { System.out.println("可乐三块五"); } }
屌丝还是多喝水吧:
[code]public class WaterDrinks extends IDrinks { @Override public void prices() { System.out.println("和我一样的穷鬼都喝水,不要钱~!"); } }
抽象饭店,无外乎吃喝(抽象工厂类):
[code]public abstract class AbstractFoodFactory { /** * 生产面条 * * @return */ public abstract INoodles createNoodles(); /** * 生产饮料 */ public abstract IDrinks createDrinks(); }
兰州大酒店(具体工厂类):
[code]public class LzlmFoodFactory extends AbstractFoodFactory { @Override public INoodles createNoodles() { return new LzNoodles();//卖兰州拉面 } @Override public IDrinks createDrinks() { return new WaterDrinks();//卖水 } }
KFC(具体工厂类):
[code]public class KFCFoodFactory extends AbstractFoodFactory { @Override public INoodles createNoodles() { return new PaoNoodles();//KFC居然卖泡面 } @Override public IDrinks create 20000 Drinks() { return new ColaDrinks();//卖可乐 } }
使用:
[code] /** * 抽象工厂方法: */ System.out.println("==============================抽象方法==============================" ) AbstractFoodFactory abstractFoodFactory1 = new KFCFoodFactory(); abstractFoodFactory1.createDrinks().prices(); abstractFoodFactory1.createNoodles().desc(); abstractFoodFactory1= new LzlmFoodFactory(); abstractFoodFactory1.createDrinks().prices(); abstractFoodFactory1.createNoodles().desc();
输出:
[code]==============================抽象方法============================== 可乐三块五 泡面 和我一样的穷鬼都喝水,不要钱~! 兰州拉面
小结:
将工厂也抽象了,在使用时,工厂和产品都是面向接口编程,OO(面向对象)的不得了。
六 个人总结和使用场景
一句话总结工厂模式:方便创建 同种产品类型的 复杂参数 对象
工厂模式重点就是适用于 构建同产品类型(同一个接口 基类)的不同对象时,这些对象new很复杂,需要很多的参数,而这些参数中大部分都是固定的,so,懒惰的程序员便用工厂模式封装之。
(如果构建某个对象很复杂,需要很多参数,但这些参数大部分都是“不固定”的,应该使用Builder模式)
为了适应程序的扩展性,拥抱变化,便衍生出了 普通工厂、抽象工厂等模式。
本文参考的文章的作者更偏向于使用多方法工厂,但我认为普通工厂和抽象工厂使用范围更广,而且更好理解。
学习参考
https://blog.csdn.net/zxt0601/article/details/52798423
转载:https://www.cnblogs.com/xuxinstyle/p/9128865.html
- 工厂模式大整理(面试问的较多)
- Java开发面试题汇总整理,大厂 HR 如何面试
- 主题:迅雷亲历面经:笔试+上机+面试(完整JAVA面试题求解大讨论)
- 【IT笔试面试题整理】笔试和面试中常见的智力题
- java基础知识记录--软件工程与设计模式(摘自张孝祥整理java面试题)
- java面试笔试题整理
- 2011Android技术面试整理附有详细答案(包括百度、新浪、中科软等多家公司笔试面试题)
- java设计模式之一 —— 工厂模式整理
- (转载)面试终结之史上最全的Java&Android面试题搜集整理
- 每天一整理-java设计模式之工厂模式模式
- 面试题整理--Java设计模式--结构型模式
- Java设计模式之四(经典面试题:工厂模式在开发中的运用)
- Java设计模式之四(经典面试题:工厂模式在开发中的运用)
- Java笔试面试题整理第三波
- [Java笔试面试知识点自整理系列]Java线程中run和start方法的区别
- java程序员面试常见面试题及答案整理
- Java笔试面试题整理第五波
- 2017最新Java基础面试笔试知识整理--java基础篇
- 2017年秋招Java面试高频面试题(个人整理)
- 【面试题】2018年最全Java面试通关秘籍汇总集!,Java面试题,BAT笔试