实战 聊聊工作中使用了哪些设计模式,java开发工程师面试

}

public static void main(String[] args) {

Order order= new Order();

try{

order.checkNullParam();

order.checkSecurity ();

order.checkBackList();

order2.checkRule();

System.out.println(“order success”);

}catch (RuntimeException e){

System.out.println(“order fail”);

}

}

}

复制代码

这段代码使用了异常来做逻辑条件判断,如果后续逻辑越来越复杂的话,会出现一些问题:如异常只能返回异常信息,不能返回更多的字段,这时候需要自定义异常类

并且,阿里开发手册规定:禁止用异常做逻辑判断

【强制】 异常不要用来做流程控制,条件控制。

说明:异常设计的初衷是解决程序运行中的各种意外情况,且异常的处理效率比条件判断方式要低很多。

如何优化这段代码呢?可以考虑责任链模式

2.2 责任链模式定义

当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式

责任链模式为请求创建了一个接收者对象的链。执行链上有多个对象节点,每个对象节点都有机会(条件匹配)处理请求事务,如果某个对象节点处理完了,就可以根据实际业务需求传递给下一个节点继续处理或者返回处理完毕。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。

责任链模式实际上是一种处理请求的模式,它让多个处理器(对象节点)都有机会处理该请求,直到其中某个处理成功为止。责任链模式把多个处理器串成链,然后让请求在链上传递:

责任链模式

打个比喻:

假设你晚上去上选修课,为了可以走点走,坐到了最后一排。来到教室,发现前面坐了好几个漂亮的小姐姐,于是你找张纸条,写上:“你好, 可以做我的女朋友吗?如果不愿意请向前传”。纸条就一个接一个的传上去了,后来传到第一排的那个妹子手上,她把纸条交给老师,听说老师40多岁未婚…

2.3 责任链模式使用

责任链模式怎么使用呢?

  • 一个接口或者抽象类

  • 每个对象差异化处理

  • 对象链(数组)初始化(连起来)

2.3.1 一个接口或者抽象类

这个接口或者抽象类,需要:

  • 有一个指向责任下一个对象的属性

  • 一个设置下一个对象的set方法

  • 给子类对象差异化实现的方法(如以下代码的doFilter方法)

/**

  • 关注公众号:捡田螺的小男孩

*/

public abstract class AbstractHandler {

//责任链中的下一个对象

private AbstractHandler nextHandler;

/**

  • 责任链的下一个对象

*/

public void setNextHandler(AbstractHandler nextHandler){

this.nextHandler = nextHandler;

}

/**

  • 具体参数拦截逻辑,给子类去实现

*/

public void filter(Request request, Response response) {

doFilter(request, response);

if (getNextHandler() != null) {

getNextHandler().filter(request, response);

}

}

public AbstractHandler getNextHandler() {

return nextHandler;

}

abstract void doFilter(Request filterRequest, Response response);

}

复制代码

2.3.2 每个对象差异化处理

责任链上,每个对象的差异化处理,如本小节的业务场景,就有参数校验对象、安全校验对象、黑名单校验对象、规则拦截对象

/**

  • 参数校验对象

**/

@Component

@Order(1) //顺序排第1,最先校验

public class CheckParamFilterObject extends AbstractHandler {

@Override

public void doFilter(Request request, Response response) {

System.out.println(“非空参数检查”);

}

}

/**

  • 安全校验对象

*/

@Component

@Order(2) //校验顺序排第2

public class CheckSecurityFilterObject extends AbstractHandler {

@Override

public void doFilter(Request request, Response response) {

//invoke Security check

System.out.println(“安全调用校验”);

}

}

/**

  • 黑名单校验对象

*/

@Component

@Order(3) //校验顺序排第3

public class CheckBlackFilterObject extends AbstractHandler {

@Override

public void doFilter(Request request, Response response) {

//invoke black list check

System.out.println(“校验黑名单”);

}

}

/**

  • 规则拦截对象

*/

@Component

@Order(4) //校验顺序排第4

public class CheckRuleFilterObject extends AbstractHandler {

@Override

public void doFilter(Request request, Response response) {

//check rule

System.out.println(“check rule”);

}

}

复制代码

2.3.3 对象链连起来(初始化)&& 使用

@Component(“ChainPatternDemo”)

public class ChainPatternDemo {

//自动注入各个责任链的对象

@Autowired

private List abstractHandleList;

private AbstractHandler abstractHandler;

//spring注入后自动执行,责任链的对象连接起来

@PostConstruct

public void initializeChainFilter(){

for(int i = 0;i<abstractHandleList.size();i++){

if(i == 0){

abstractHandler = abstractHandleList.get(0);

}else{

AbstractHandler currentHander = abstractHandleList.get(i - 1);

AbstractHandler nextHander = abstractHandleList.get(i);

currentHander.setNextHandler(nextHander);

}

}

}

//直接调用这个方法使用

public Response exec(Request request, Response response) {

abstractHandler.filter(request, response);

return response;

}

public AbstractHandler getAbstractHandler() {

return abstractHandler;

}

public void setAbstractHandler(AbstractHandler abstractHandler) {

this.abstractHandler = abstractHandler;

}

}

复制代码

运行结果如下:

非空参数检查

安全调用校验

校验黑名单

check rule

复制代码

3. 模板方法模式


3.1 业务场景

假设我们有这么一个业务场景:内部系统不同商户,调用我们系统接口,去跟外部第三方系统交互(http方式)。走类似这么一个流程,如下:

一个请求都会经历这几个流程:

  • 查询商户信息

  • 对请求报文加签

  • 发送http请求出去

  • 对返回的报文验签

这里,有的商户可能是走代理出去的,有的是走直连。假设当前有A,B商户接入,不少伙伴可能这么实现,伪代码如下:

// 商户A处理句柄

CompanyAHandler implements RequestHandler {

Resp hander(req){

//查询商户信息

queryMerchantInfo();

//加签

signature();

//http请求(A商户假设走的是代理)

httpRequestbyProxy()

//验签

verify();

}

}

// 商户B处理句柄

CompanyBHandler implements RequestHandler {

Resp hander(Rreq){

//查询商户信息

queryMerchantInfo();

//加签

signature();

// http请求(B商户不走代理,直连)

httpRequestbyDirect();

// 验签

verify();

}

}

复制代码

假设新加一个C商户接入,你需要再实现一套这样的代码。显然,这样代码就重复了,一些通用的方法,却在每一个子类都重新写了这一方法

如何优化呢?可以使用模板方法模式

3.2 模板方法模式定义

定义一个操作中的算法的骨架流程,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。它的核心思想就是:定义一个操作的一系列步骤,对于某些暂时确定不下来的步骤,就留给子类去实现,这样不同的子类就可以定义出不同的步骤。

打个通俗的比喻:

模式举例:追女朋友要先“牵手”,再“拥抱”,再“接吻”, 再“拍拍…额…手”。至于具体你用左手还是右手牵,无所谓,但是整个过程,定了一个流程模板,按照模板来就行。

3.3 模板方法使用

  • 一个抽象类,定义骨架流程(抽象方法放一起)

  • 确定的共同方法步骤,放到抽象类(去除抽象方法标记)

  • 不确定的步骤,给子类去差异化实现

我们继续那以上的举例的业务流程例子,来一起用 模板方法优化一下哈:

3.3.1 一个抽象类,定义骨架流程

因为一个个请求经过的流程为一下步骤:

  • 查询商户信息

  • 对请求报文加签

  • 发送http请求出去

  • 对返回的报文验签

所以我们就可以定义一个抽象类,包含请求流程的几个方法,方法首先都定义为抽象方法哈:

/**

  • 抽象类定义骨架流程(查询商户信息,加签,http请求,验签)

*/

abstract class AbstractMerchantService {

//查询商户信息

abstract queryMerchantInfo();

//加签

abstract signature();

//http 请求

abstract httpRequest();

// 验签

abstract verifySinature();

}

复制代码

3.3.2 确定的共同方法步骤,放到抽象类

abstract class AbstractMerchantService {

//模板方法流程

Resp handlerTempPlate(req){

//查询商户信息

queryMerchantInfo();

//加签

signature();

//http 请求

httpRequest();

// 验签

verifySinature();

}

// Http是否走代理(提供给子类实现)

abstract boolean isRequestByProxy();

}

复制代码

3.3.3 不确定的步骤,给子类去差异化实现

因为是否走代理流程是不确定的,所以给子类去实现。

商户A的请求实现:

CompanyAServiceImpl extends AbstractMerchantService{

Resp hander(req){

return handlerTempPlate(req);

}

//走http代理的

boolean isRequestByProxy(){

return true;

}

复制代码

商户B的请求实现:

CompanyBServiceImpl extends AbstractMerchantService{

Resp hander(req){

return handlerTempPlate(req);

}

//公司B是不走代理的

boolean isRequestByProxy(){

return false;

}

复制代码

4. 观察者模式


4.1 业务场景

登陆注册应该是最常见的业务场景了。就拿注册来说事,我们经常会遇到类似的场景,就是用户注册成功后,我们给用户发一条消息,又或者发个邮件等等,因此经常有如下的代码:

void register(User user){

insertRegisterUser(user);

sendIMMessage();

sendEmail();

}

复制代码

这块代码会有什么问题呢? 如果产品又加需求:现在注册成功的用户,再给用户发一条短信通知。于是你又得改register方法的代码了。。。这是不是违反了开闭原则啦。

void register(User user){

insertRegisterUser(user);

sendIMMessage();

sendMobileMessage();

sendEmail();

}

复制代码

并且,如果调发短信的接口失败了,是不是又影响到用户注册了?!这时候,是不是得加个异步方法给通知消息才好。。。

实际上,我们可以使用观察者模式优化。

4.2 观察者模式定义

观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被完成业务的更新。

观察者模式属于行为模式,一个对象(被观察者)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。它的主要成员就是观察者和被观察者

  • 被观察者(Observerable):目标对象,状态发生变化时,将通知所有的观察者。

  • 观察者(observer):接受被观察者的状态变化通知,执行预先定义的业务。

使用场景: 完成某件事情后,异步通知场景。如,登陆成功,发个IM消息等等。

4.3 观察者模式使用

观察者模式实现的话,还是比较简单的。

  • 一个被观察者的类Observerable ;

  • 多个观察者Observer ;

  • 观察者的差异化实现

  • 经典观察者模式封装:EventBus实战

4.3.1 一个被观察者的类Observerable 和 多个观察者Observer

public class Observerable {

private List observers

= new ArrayList();

private int state;

public int getState() {

return state;

}

public void setState(int state) {

notifyAllObservers();

}

//添加观察者

public void addServer(Observer observer){

observers.add(observer);

}

//移除观察者

public void removeServer(Observer observer){

observers.remove(observer);

}

//通知

public void notifyAllObservers(int state){

if(state!=1){

System.out.println(“不是通知的状态”);

return ;

}

for (Observer observer : observers) {

observer.doEvent();

}

}

}

复制代码

4.3.2 观察者的差异化实现

//观察者

interface Observer {

void doEvent();

}

//Im消息

IMMessageObserver implements Observer{

void doEvent(){

System.out.println(“发送IM消息”);

}

}

//手机短信

MobileNoObserver implements Observer{

void doEvent(){

System.out.println(“发送短信消息”);

}

}

//EmailNo

EmailObserver implements Observer{

void doEvent(){

System.out.println(“发送email消息”);

}

}

复制代码

4.3.3 EventBus实战

自己搞一套观察者模式的代码,还是有点小麻烦。实际上,Guava EventBus 就封装好了,它 提供一套基于注解的事件总线,api可以灵活的使用,爽歪歪。

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

最后

分享一套我整理的面试干货,这份文档结合了我多年的面试官经验,站在面试官的角度来告诉你,面试官提的那些问题他最想听到你给他的回答是什么,分享出来帮助那些对前途感到迷茫的朋友。

面试经验技巧篇
  • 经验技巧1 如何巧妙地回答面试官的问题
  • 经验技巧2 如何回答技术性的问题
  • 经验技巧3 如何回答非技术性问题
  • 经验技巧4 如何回答快速估算类问题
  • 经验技巧5 如何回答算法设计问题
  • 经验技巧6 如何回答系统设计题
  • 经验技巧7 如何解决求职中的时间冲突问题
  • 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
  • 经验技巧9 在被企业拒绝后是否可以再申请
  • 经验技巧10 如何应对自己不会回答的问题
  • 经验技巧11 如何应对面试官的“激将法”语言
  • 经验技巧12 如何处理与面试官持不同观点这个问题
  • 经验技巧13 什么是职场暗语

面试真题篇
  • 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
  • 真题详解2 某知名社交平台软件工程师笔试题
  • 真题详解3 某知名安全软件服务提供商软件工程师笔试题
  • 真题详解4 某知名互联网金融企业软件工程师笔试题
  • 真题详解5 某知名搜索引擎提供商软件工程师笔试题
  • 真题详解6 某初创公司软件工程师笔试题
  • 真题详解7 某知名游戏软件开发公司软件工程师笔试题
  • 真题详解8 某知名电子商务公司软件工程师笔试题
  • 真题详解9 某顶级生活消费类网站软件工程师笔试题
  • 真题详解10 某知名门户网站软件工程师笔试题
  • 真题详解11 某知名互联网金融企业软件工程师笔试题
  • 真题详解12 国内某知名网络设备提供商软件工程师笔试题
  • 真题详解13 国内某顶级手机制造商软件工程师笔试题
  • 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
  • 真题详解15 某著名社交类上市公司软件工程师笔试题
  • 真题详解16 某知名互联网公司软件工程师笔试题
  • 真题详解17 某知名网络安全公司校园招聘技术类笔试题
  • 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题

资料整理不易,点个关注再走吧

最后

分享一套我整理的面试干货,这份文档结合了我多年的面试官经验,站在面试官的角度来告诉你,面试官提的那些问题他最想听到你给他的回答是什么,分享出来帮助那些对前途感到迷茫的朋友。

面试经验技巧篇
  • 经验技巧1 如何巧妙地回答面试官的问题
  • 经验技巧2 如何回答技术性的问题
  • 经验技巧3 如何回答非技术性问题
  • 经验技巧4 如何回答快速估算类问题
  • 经验技巧5 如何回答算法设计问题
  • 经验技巧6 如何回答系统设计题
  • 经验技巧7 如何解决求职中的时间冲突问题
  • 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
  • 经验技巧9 在被企业拒绝后是否可以再申请
  • 经验技巧10 如何应对自己不会回答的问题
  • 经验技巧11 如何应对面试官的“激将法”语言
  • 经验技巧12 如何处理与面试官持不同观点这个问题
  • 经验技巧13 什么是职场暗语

[外链图片转存中…(img-utiIu3Ii-1711107276126)]

面试真题篇
  • 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
  • 真题详解2 某知名社交平台软件工程师笔试题
  • 真题详解3 某知名安全软件服务提供商软件工程师笔试题
  • 真题详解4 某知名互联网金融企业软件工程师笔试题
  • 真题详解5 某知名搜索引擎提供商软件工程师笔试题
  • 真题详解6 某初创公司软件工程师笔试题
  • 真题详解7 某知名游戏软件开发公司软件工程师笔试题
  • 真题详解8 某知名电子商务公司软件工程师笔试题
  • 真题详解9 某顶级生活消费类网站软件工程师笔试题
  • 真题详解10 某知名门户网站软件工程师笔试题
  • 真题详解11 某知名互联网金融企业软件工程师笔试题
  • 真题详解12 国内某知名网络设备提供商软件工程师笔试题
  • 真题详解13 国内某顶级手机制造商软件工程师笔试题
  • 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
  • 真题详解15 某著名社交类上市公司软件工程师笔试题
  • 真题详解16 某知名互联网公司软件工程师笔试题
  • 真题详解17 某知名网络安全公司校园招聘技术类笔试题
  • 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题

[外链图片转存中…(img-Jz9z8A40-1711107276126)]

资料整理不易,点个关注再走吧

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 10
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值