[关闭]
@TryLoveCatch 2023-02-01T16:28:35.000000Z 字数 2669 阅读 572

Java知识体系之设计模式相关问题

Java知识体系


设计模式有哪些?

设计模式一般分为三种:创建型、结构型、行为型。

简单工厂、工厂方法和抽象工厂三者有什么区别

适配器模式与装饰器模式有什么区别?

适配器模式和代理模式之间有什么不同?

装饰器模式和代理模式之间有什么不同?

https://www.cnblogs.com/fanguangdexiaoyuer/p/10288581.html

相同点:装饰类(代理类)与被装饰类(被代理类)都需要实现相同的接口;

装饰模式主要是强调对类中代码的拓展。
代理模式则偏向于委托类的访问限制。
换句话 说,用代理模式,代理类(proxy class)可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。并且,当我们使用装饰器模 式的时候,我们通常的做法是将原始对象作为一个参数传给装饰者的构造器。

我们可以用另外一句话来总结这些差别:使用代理模式,代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造。

为什么是双重校验?

第一次校验:这个是为了代码提高代码执行效率,由于单例模式只需要创建一次实例即可,所以当创建了一个实例之后,再次调用getInstance()就不必要进入同步代码块,不用竞争锁,直接返回前面创建的实例即可。

第二次校验:是防止再次创建实例,避免这个多线程导致多次创建实例的问题。

所以说:两次校验都必不可少!

为什么给静态对象的定义加上volatile锁?

这里volatile的作用仅仅是阻止指令重排序,不涉及可见性问题,可见性已经由synchronized来保证了。
为什么要用到volatile的指令重排序功能呢?
初始化对象的指令可能会被重排成:  
(1)分配内存空间。  
(2)将内存空间的地址赋值给对应的引用。  
(3)初始化对象
问题的关键在于,如果A线程正好初始化到了第(2)步的时候,正好有其它线程B来获取这个对象,
那线程B能不能看到这个由A初始化但是还没初始化完毕的对象呢?答案是可能会看到这个未完全初始化的对象, 因为这里初始化的是一个共享变量。
为什么初始化共享变量会带来问题呢?
如果共享变量的引用已经和构造器的调用内联了, 即使构造器未完成初始化, 共享变量也可能会立即被更新,也就是说其它线程可能会看到一个未经完全初始化的对象。
所以,这里使用的是volatile禁止重排的功能。

过多if-else怎么处理呢?

https://www.zhihu.com/question/344856665/answer/1218475922

遇到大量if记住下面的口诀:

互斥条件表驱动
嵌套条件校验链
短路条件早return
零散条件可组合

互斥条件表驱动

对于逻辑表达模式固定的 if...else 代码,可以通过某种映射关系,将逻辑表达式用表格的方式表示;再使用表格查找的方式,找到某个输入所对应的处理函数,使用这个处理函数进行运算。

表示几个条件之间是冲突的,不可能同时达成的。比如说一个数字,它不可能同时是4和2。在这种情况下用表驱动就非常合适,表驱动的核心是key-handler,拿某个key去对应某个handler,只要条件符合key,那么就执行对应的handler。

其实,互斥条件,有两种情况

  1. if (state == OPEN) {
  2. // xxx
  3. } else if (state == CLOSE) {
  4. // xxx
  5. } else if (state == ADD) {
  6. // xxx
  7. } else if (state == REMOVE) {
  8. // xxx
  9. }

这种就可以实用表驱动

还有一种是这样:

  1. if (class1.isHit1(object)) {
  2. // xxx
  3. } else if (class2.isHit2(object)) {
  4. // xxx
  5. } else if (class3.isHit3(object)) {
  6. // xxx
  7. } else if (class4.isHit4(object)) {
  8. // xxx
  9. }

这种就可以实用责任链的方式

嵌套条件校验链

互斥条件,表示几个条件之间是冲突的,不可能同时达成的。比如说一个数字,它不可能同时是4和2。在这种情况下用表驱动就非常合适,表驱动的核心是key-handler,拿某个key去对应某个handler,只要条件符合key,那么就执行对应的handler。
嵌套条件,表示几个条件是必须同时达成的,比如,只有在手机号码格式正确的情况下才执行某个操作,格式正确就包括必须是字符串、长度为11位、所有位都是数字这些条件,那么就可以使用校验链,比如通过描述的校验链:"string&size:11&numchar:0,*"。能用的形式很多,你可以直接使用&&逻辑运算符拼接条件,也可以把规则写成Validator。
短路条件,表示只要某个条件满足了,那么就不用再继续下面的任何操作了。比如传进来的参数是null、参数如果为0,就不会有其他操作等情况,都可以聚合这些条件,在一开始的时候就判断并且直接返回,或者程序在中间会产生一些可以直接判断为不需要继续往下操作的条件,那么同样是直接在当场就return。
零散条件,是指存在以上三种任意组合的条件形式,那么就可以通过组合这些解决方案。例如,遇到null,直接短路返回,然后之后的代码使用表驱动来区分互斥条件,在达成某个互斥条件的时候,通过校验链来验证嵌套条件等。

参考

https://blog.csdn.net/zhaohongfei_358/article/details/115085887
https://blog.csdn.net/weixin_44471490/article/details/108929289
https://www.zhihu.com/question/344856665/answer/1218475922

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注