设计模式能不能不问了?我面试都问烦了
面试官:我看你的简历写着熟悉常见的设计模式,要不你来简单聊聊你熟悉哪几个吧?
候选者:常见的工厂模式、代理模式、模板方法模式、责任链模式、单例模式、包装设计模式、策略模式等都是有所了解的
候选者:项目手写代码用得比较多的,一般就模板方法模式、责任链模式、策略模式、单例模式吧
候选者:像工厂模式、代理模式这种,手写倒是不多,但毕竟Java后端一般环境下都用Spring嘛,所以还是比较熟悉的。
面试官:要不你来手写下单例模式呗?
候选者:单例模式一般会有好几种写法
候选者:饿汉式、简单懒汉式(在方法声明时加锁)、DCL双重检验加锁(进阶懒汉式)、静态内部类(优雅懒汉式)、枚举
候选者:所谓「饿汉式」指的就是还没被用到,就直接初始化了对象。所谓「懒汉式」指的就是等用到的时候,才进行初始化
候选者:那我就都写写吧,反正就那些代码
面试官:那你们用的哪种比较多?
候选者:一般我们项目里用静态内部类的方式实现单例会比较多(如果没有Spring的环境下),代码简洁易读
候选者:如果有Spring环境,那还是直接交由Spring容器管理会比较方便(Spring默认就是单例的)
候选者:枚举一般我们就用它来做「标识」吧,而DCL这种方式也有同学会在项目里写(在一些源码里也能看到其身影),但总体太不利于阅读和理解(:
候选者:总的来说,用哪一种都可以的,关键我觉得要看团队的代码风格吧(保持一致就行),即便都用「饿汉式」也没啥大的问题(现在内存也没那么稀缺,我认为可读性比较重要)
面试官:嗯…
面试官:我看你在DCL的单例代码上,写了volatile修饰嘛?为什么呢?
候选者:你不记得我们曾经聊过volatile的了嘛?指令是有可能乱序执行的(编译器优化导致乱序、CPU缓存架构导致乱序、CPU原生重排导致乱序)
候选者:在代码new Object的时候,不是一条原子的指令,它会由几个步骤组成,在这过程中,就可能会发生指令重排的问题,而volatile这个关键字就可以避免指令重排的发生。
面试官:那你说下你在项目里用到的设计模式吧?
候选者:嗯,比如说,我这边在处理请求的时候,会用到责任链模式进行处理(减免if else 并且让项目结构更加清晰)
候选者:在处理公共逻辑时,会使用模板方法模式进行抽象,具体不同的逻辑会由不同的实现类处理(每种消息发送前都需要经过文案校验,所以可以把文案校验的逻辑写在抽象类上)
候选者:代理模式手写的机会比较少(因为项目一般有Spring环境,直接用Spring 的AOP代理就好了)
候选者:我之前使用过AOP把「监控客户端」封装以「注解」的方式进行使用(不用以硬编码的方式来进行监控,只要有注解就行了)
面试官:那你能聊聊Spring常见的设计模式嘛?
候选者:比如,Spring IOC容器可以理解为应用了「工厂模式」(通过ApplicationContext或者BeanFactory去获取对象)
候选者:Spring的对象默认都是单例的,所以肯定是用了「单例模式」(源码里对单例的实现是用的DCL来实现单例)
候选者:Spring AOP的底层原理就是用了「代理模式」,实现可能是JDK 动态代理,也可能是CGLIB动态代理
候选者:Spring有很多地方都用了「模板方法模式」,比如事务管理器(AbstractPlatformTransactionManager),getTransaction定义了框架,其中很多都由子类实现
候选者:Spring的事件驱动模型用了「观察者模式」,具体实现就是ApplicationContextEvent、ApplicationListener
面试官:嗯,了解…