当前位置:   article > 正文

【设计模式】精品面试题10道

【设计模式】精品面试题10道

【设计模式】精品面试题10道

加个说明:我的初心是Java每个技术栈整理个100道面试题,现在的底子是哪吒的《208道面试题》
后续我会把自己有价值的题和面试真题添加进入,也对一部分题的错误之处做了重新的修改
反正不会用于盈利目的,整理和自我学习,有取自别人的地方,请理解也心存感激   
                                                                   --阿呆布衣酷
  • 1
  • 2
  • 3
  • 4

1.请列举在JDK中几个常用的设计模式?
2.什么是设计模式?你是否在你的代码里面使用过任何设计模式
3. Java中什么叫单例设计模式?请用Java写出线程安全的单例模式?
4.在Java中,什么叫观察者设计模式(observer design pattern)?
5.使用工厂模式最主要的好处是什么?在哪里使用?
6.请解释自动装配模式的区别?
7.举一个用Java实现的装饰模式(decorator design pattern)?它是作用于对象层次还是类层次?
8.Java实现懒汉单例模式?
9.Java实现饿汉单例模式?


1.请列举在JDK中几个常用的设计模式?

1.单例模式
作用:保证类只有一个实例
JDK中体现:Runtime2.静态工厂模式
作用:代替构造函数创建对象,方法名比构造函数清晰
JDK中体现:Integer.valueOf(),Class.forName()

3.抽象工厂模式
作用:创建某一种类的对象
JDK中体现:java.sql包

4.原型模式
clone()
原型模式的本质是拷贝原型来创建新的对象,
拷贝是比new更快的创建对象的方法,
当需要大批量创建新对象而且都是同一类的对象的时候考虑使用原型模式

一般的克隆只是浅拷贝(对象的hash值不一样,但是对象里面的成员变量的hash值是一样的)
有些场景需要深拷贝,这时我们就要重写clone()方法,以ArrayList为例

5.适配器模式
作用:使不兼容的接口相容
JDK中体现:InputStreamOutputStream

6.装饰器模式
作用:为类添加新的功能,防止类继承带来的类爆炸
JDK中体现:IO类、CollectionsList

7.外观模式
作用:封装一组交互类,一致对外提供接口
JDK中体现:logging包

8.享元模式
作用:共享对象、节省内存
JDK中体现:Integer.valueOf()String常量池

9.代理模式
作用:
1.透明调用被代理对象,无需知道复杂实现细节
2.增加被代理类的功能
JDK中体现:动态代理

10.迭代器模式
作用:将集合的迭代和集合本身分离
JDK中体现:Iterator

11.命令模式
作用:封装操作,使接口一致
JDK中体现:RunnableCallableThreadPoolExecutor
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

2.什么是设计模式?你是否在你的代码里面使用过任何设计模式

一:什么是设计模式?
设计模式是解决软件开发某些特定问题而提出的一些解决方案,
也可以理解为解决问题的一些固定思路

通过设计模式可以帮助我们增强代码的可复用性、可扩展性、灵活性
我们使用设计模式的最终目的是实现代码的高内聚、低耦合

二:设计模式的七大原则
1.单一职责原则
2.接口隔离原则
3.依赖倒转原则
4.里氏替换原则
5.开闭原则
6.迪米特原则
7.合成复用原则

三:你是否在你的代码里面使用过任何设计模式?
1.单例模式
JDK中的runtime
Spring中的singleton

2.简单工厂模式
SpringBeanFactory,
根据传入一个唯一标识来创建bean对象

3.原型模式
clone()

4.代理模式
Spring的AOP中,
Spring实现AOP功能的原理就是代理模式
一:JDK动态代理
二:CGLIB动态代理,使用Advice(通知)对类进行方法级别的切面增强

5.装饰器模式
为类添加新的功能,防止类爆炸
IO流、数据源包装、Spring中用到的装饰器模式表现在Wrapper
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

3. Java中什么叫单例设计模式?请用Java写出线程安全的单例模式?

1.保证程序只有一个对象实例,叫做单例模式
2.内部类的方式实现单例模式,是线程安全的
3.双重验证方式实现单例模式也是线程安全的
  • 1
  • 2
  • 3

4.在Java中,什么叫观察者设计模式(observer design pattern)?

一:观察者模式是一种一对多的依赖关系,
让多个观察者同时监听某一主体对象
当这个主体对象发生变化时,
会通知所有观察者对象,使它们能够自动更新自己

二:Java提供对观察者模式的支持
在Java语言的java.util库里面,
提供了一个Observable类以及一个Observer接口,构成Java语言对观察者模式的支持
1.Observer接口
这个接口只定义了一个方法,即update()方法,
当被观察者对象的状态发生变化时,
被观察者对象的notifyObservers()方法就会调用这一方法

public interface Observer{
    void update(Observable o,Object arg);
}

2.Observable类
被观察者类都是java.util.Observable类的子类
java.util.Observable提供公开的方法支持观察者对象
这些方法中有两个对Observable的子类非常重要:
一个是setChanged()
setChanged()方法被调用之后设置一个内部标记变量,代表被观察者的对象发生了变化
另一个是notifyObservers()
notifyObservers()方法被调用时,会调用所有登记过的观察者对象的update()方法
使这些观察者可以更新自己
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

5.使用工厂模式最主要的好处是什么?在哪里使用?

1.工厂模式的好处:
良好的封装性、代码结构清晰
扩展性好,如果想增加一个产品,只需扩展一个工厂类即可
典型的解耦框架

2.在哪里使用工厂模式?
需要生成对象的地方
不同数据库的访问
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

6.请解释自动装配模式的区别?

有五种自动装配的方式,可以用来指导Spring容器用自动装配方式来进行依赖注入
1.no
默认的方式是不进行自动装配,通过显式设置ref属性来进行装配

2.byName
通过参数名来自动装配,
Spring容器在配置文件中发现bean的autowire属性被设置成byName,
之后容器试图匹配、装配和该bean的属性具有相同名字的bean

3.byType
通过参数类型自动装配,
Spring容器在配置文件中发现bean的autowire属性被设置成byType,
之后容器试图匹配、装配和该bean的属性具有相同类型的bean
如果有多个bean符合条件,则抛出错误

4.constructor
这个方式类似与byType,但是要提供给构造器参数,
如果没有确定的带参数的构造器参数类型,将会抛出异常

5.autodetect
首先尝试使用constructor来自动装配,
如果无法工作,则使用byType方式
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

7.举一个用Java实现的装饰模式(decorator design pattern)?它是作用于对象层次还是类层次?

Java IO中运用了装饰器模式,inputStream作为抽象类,其下有几个实现类,表示从不同的数据源输入:

byteArrayInputStream
fileInputStream
StringBufferInputStream
PipedInputStream,从管道产生输入;
SequenceInputStream,可将其他流收集合并到一个流内;
FilterInputStream作为装饰器在JDK中是一个普通类,其下面有多个具体装饰器比如BufferedInputStreamDataInputStream等。

FilterInputStream内部封装了基础构件:

protected volatile InputStream in;BufferedInputStream在调用其read()读取数据时会委托基础构件来进行更底层的操作,而它自己所起的装饰作用就是缓冲,在源码中可以很清楚的看到这一切。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

8.Java实现懒汉单例模式?

懒汉单例模式是指在需要时才创建对象实例,而不是在类加载时就创建对象实例。下面是Java实现懒汉单例模式的示例代码:

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
在上述代码中,Singleton类的构造方法是私有的,因此外部无法直接创建对象实例。getInstance()方法是用来获取Singleton类的唯一实例的,它首先判断instance是否为null,如果为null则创建一个新的Singleton对象,否则直接返回已经存在的实例。

需要注意的是,由于懒汉单例模式在多线程环境下存在线程安全问题,因此在getInstance()方法中需要对instance进行线程同步,以保证多线程环境下仍然能够正确地返回Singleton实例。

为了保证线程安全性,可以通过synchronized关键字来实现线程同步,或者使用双重检查锁定机制(Double-Checked Locking),如下所示:

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
或者:

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
在第一种方式中,getInstance()方法被加上了synchronized关键字,以保证线程安全性。在第二种方式中,使用了双重检查锁定机制,即先判断instance是否为null,如果为null,则对Singleton类进行加锁,然后再次判断instance是否为null,如果仍为null,则创建一个新的Singleton对象。由于使用了volatile关键字,可以确保在多线程环境下,对instance的读取和写入操作都是原子性的,从而避免了线程安全问题。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

9.Java实现饿汉单例模式?

以下是Java实现饿汉单例模式的代码:

public class Singleton {
    // 私有化构造函数
    private Singleton() {}
    // 创建唯一实例
    private static Singleton instance = new Singleton();
    // 获取实例的静态方法
    public static Singleton getInstance() {
        return instance;
    }
}
在饿汉单例模式中,实例化对象是在类加载时完成的,
因此可以保证线程安全,但可能会浪费一些内存空间。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

10.创建线程安全的单例有那些实现方法?

创建线程安全的单例有以下几种实现方法:

一:饿汉式单例模式
在类加载时即创建单例对象,线程安全,但可能会浪费一些内存空间。

public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

二:懒汉式单例模式
在第一次使用时才创建单例对象,但线程不安全,需要加锁。

public class Singleton {
    private static Singleton INSTANCE;
    private Singleton() {}
    public static synchronized Singleton getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Singleton();
        }
        return INSTANCE;
    }
}

三:双重校验锁单例模式
既保证线程安全,又能在第一次使用时才创建单例对象,但需要注意volatile关键字的使用。

public class Singleton {
    private static volatile Singleton INSTANCE;
    private Singleton() {}
    public static Singleton getInstance() {
        if (INSTANCE == null) {
            synchronized (Singleton.class) {
                if (INSTANCE == null) {
                    INSTANCE = new Singleton();
                }
            }
        }
        return INSTANCE;
    }
}

四:静态内部类单例模式
利用静态内部类的特性,在第一次使用时才创建单例对象,且线程安全,是最佳实践。

public class Singleton {
    private Singleton() {}
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

五:枚举类型在Java中是线程安全的,因此可以使用枚举类型实现线程安全的单例模式。实现方式如下:

public enum Singleton {
    INSTANCE;
    public void doSomething() {
        // do something
    }
}
调用时,可以直接通过Singleton.INSTANCE获取单例对象。
该方法不仅线程安全,还可以防止反序列化破坏单例模式。
因为枚举类型在反序列化时,会比较序列化前后的类对象,
如果不一致则会抛出异常,从而防止了反序列化破坏单例模式。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/157572
推荐阅读
相关标签
  

闽ICP备14008679号