1、请列举出在 JDK 中几个常用的设计模式?
1、单例模式
作用:保证类只有一个实例。
JDK中体现:Runtime类。
2、静态工厂模式
作用:代替构造函数创建对象,方法名比构造函数清晰。
JDK中体现:Integer.valueOf、Class.forName
3、抽象工厂
作用:创建某一种类的对象。
JDK中体现:Java.sql包。
4、原型模式
clone();
原型模式的本质是拷贝原型来创建新的对象,拷贝是比new更快的创建对象的方法,当需要大批量创建新对象而且都是同一个类的对象的时候考虑使用原型模式。
一般的克隆只是浅拷贝(对象的hash值不一样,但是对象里面的成员变量的hash值是一样的)。
有些场景需要深拷贝,这时我们就要重写clone方法,以ArrayList为例:
5、适配器模式
作用:使不兼容的接口相容。
JDK中体现:InputStream、OutputStream。
6、装饰器模式
作用:为类添加新的功能,防止类继承带来的类爆炸。
JDK中体现:io类、Collections、List。
7、外观模式
作用:封装一组交互类,一直对外提供接口。
JDK中体现:logging包。
8、享元模式
作用:共享对象、节省内存。
JDK中体现:Integer.valueOf、String常量池。
9、代理模式
作用:
(1)透明调用被代理对象,无须知道复杂实现细节;
(2)增加被代理类的功能;
JDK中体现:动态代理。
10、迭代器模式
作用:将集合的迭代和集合本身分离。
JDK中体现:Iterator
11、命令模式
作用:封装操作,使接口一致。
JDK中体现:Runable、Callable、ThreadPoolExecutor。
2、什么是设计模式?你是否在你的代码里面使用过任何设计模式?
1、什么是设计模式?
设计模式是解决软件开发某些特定问题而提出的一些解决方案,也可以理解为解决问题的一些固定思路。
通过设计模式可以帮助我们增强代码的可复用性、可扩展性、灵活性。
我们使用设计模式的最终目的是实现代码的高内聚、低耦合。
2、设计模式的七大原则
- 单一职责原则
- 接口隔离原则
- 依赖倒转原则
- 里式替换原则
- 开闭原则
- 迪米特法则
- 合成复用原则
3、你是否在你的代码里面使用过任何设计模式?
(1)单例模式
JDK种的runtime,Spring种的singeton。
(2)简单工厂模式
Spring的BeanFactory,根据传入一个唯一标识来获得bean对象。
(3)原型模式
clone()
(4)代理模式
Spring的AOP中,Spring实现AOP功能的原理就是代理模式,①JDK动态代理。②CGLIB动态代理,使用Advice(通知)对类进行方法级别的切面增强。
(5)装饰器模式
为类添加新的功能,防止类爆炸;
IO流、数据源包装,Spring中用到的装饰器模式表现在Wrapper。
3、Java 中什么叫单例设计模式?请用 Java 写出线程安全的单例模式
保证程序只有一个对象的实例,叫做单例模式;
内部类的方式实现单例模式,是线程安全的;
双重验证方式实现单例模式也是线程安全的;
4、在 Java 中,什么叫观察者设计模式(observer design pattern)?
1、观察者模式是一种一对多的依赖关系,让多个观察者同时监听某一主题对象。当这个主题对象发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
2、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(),另一个是notifyObservers()。第一方法setChanged()被调用之后会设置一个内部标记变量,代表被观察者对象的状态发生了变化。第二个是notifyObservers(),这个方法被调用时,会调用所有登记过的观察者对象的update()方法,使这些观察者对象可以更新自己。
5、使用工厂模式最主要的好处是什么?在哪里使用?
1、工厂模式好处
良好的封装性、代码结构清晰;
扩展性好,如果想增加一个产品,只需扩展一个工厂类即可;
典型的解耦框架;
2、在哪里使用?
需要生成对象的地方;
不同数据库的访问;
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 方式。
7、举一个用 Java 实现的装饰模式(decorator design pattern)?它是作用于对象层次还是类层次?
在Java IO中运用了装饰器模式,inputStream作为抽象类,其下有几个实现类,表示从不同的数据源输入:
- byteArrayInputStream
- fileInputStream
- StringBufferInputStream
- PipedInputStream,从管道产生输入;
- SequenceInputStream,可将其他流收集合并到一个流内;
FilterInputStream作为装饰器在JDK中是一个普通类,其下面有多个具体装饰器比如 BufferedInputStream、DataInputStream等。
FilterInputStream内部封装了基础构件:
protected volatile InputStream in;
而BufferedInputStream在调用其read()读取数据时会委托基础构件来进行更底层的操作,而它自己所起的装饰作用就是缓冲,在源码中可以很清楚的看到这一切。