1 Star 0 Fork 31

霍月龙 / Ebooks

forked from dearHaoGeGe / Ebooks 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
设计模式经典面试题集锦,学会再也不怕面试了!.md 16.16 KB
一键复制 编辑 原始数据 按行查看 历史

设计模式经典面试题集锦,学会再也不怕面试了!

全部面试题答案,更新日期:01月30日,直接下载吧!

下载链接:高清500+份面试题资料及电子书,累计 10000+ 页大厂面试题 PDF

设计模式

题1:Java 中什么是抽象工厂模式?

抽象工厂简单地说是工厂的工厂,抽象工厂可以创建具体工厂,由具体工厂来产生具体产品。

1)创建共用接口,代码如下:

package com.yoodb;
 
public interface Dinner{
    public void eat();
}

2)创建实现类,代码如下:

package com.yoodb;
 
public class CatDinner implements Dinner{
 
    @Override
    public void eat() {
        // TODO Auto-generated method stub
        System.out.println("小猫来吃饭了!");
    }
 
}
package com.yoodb;
 
public class DogDinner implements Dinner{
 
    @Override
    public void eat() {
        // TODO Auto-generated method stub
        System.out.println("小狗来吃饭了!");
    }
     
}

3)创建接口,代码如下:

package com.yoodb;
 
public interface Provider {  
        public Sender produce();  
}

4)创建两个工厂,代码如下:

package com.yoodb;
 
public class CatFactory implements Provider{
     
    public Dinner produce(){
        return new CatDinner();
    }
}
package com.yoodb;
 
public class DogFactory implements Provider{
     
    public Dinner produce(){
        return new DogDinner();
    }
}

5)main函数测试,代码如下:

package com.yoodb;
 
public class FactoryTest {
    public static void main(String[] args) {
        Provider factory = new DogFactory();
        Dinner dinner = factory.produce();
        dinner.eat();
    }
}

题2:Java 中外观模式有什么优势?

1)它对客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。

2)它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。松耦合关系使得子系统的组件变化不会影响到它的客户。Facade模式有助于建立层次结构系统,也有助于对对象之间的依赖关系分层。Facade模式可以消除复杂的循环依赖关系。

这一点在客户程序与子系统是分别实现的时候尤为重要。在大型软件系统中降低编译依赖性至关重要。在子系统类改变时,希望尽量减少重编译工作以节省时间。用Facade可以降低编译依赖性,限制重要系统中较小的变化所需的重编译工作。Facade模式同样也有利于简化系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。

3)如果应用需要,它并不限制它们使用子系统类。因此你可以在系统易用性和通用性之间加以选择。

题3:Java 中单例模式使用时有哪些注意事项?

1、使用时不能用反射模式创建单例,否则会实例化一个新的对象。

2、使用懒单例模式时注意线程安全问题。

3、饿单例模式和懒单例模式构造方法都是私有的,因而是不能被继承的,有些单例模式可以被继承(如登记式模式)。

题4:Java 中代理模式如何实现 CGLIB 动态代理?

CGLIB动态代理和jdk代理一样,使用反射完成代理,不同的是他可以直接代理类(jdk动态代理不行,他必须目标业务类必须实现接口),CGLIB动态代理底层使用字节码技术,CGLIB动态代理不能对 final类进行继承。(CGLIB动态代理需要导入jar包)。

CGLIB动态代理原理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

1)接口,具体代码如下:

package com.yoodb.blog;

public interface UserDao {
    void save();
}

2)实现业务逻辑类,具体代码如下:

package com.yoodb.blog;

//接口实现类
public class UserDaoImpl implements UserDao {
	public void save() {
		System.out.println("保存数据方法");
	}
}

3)代理主要类,具体代码如下:

package com.yoodb.blog;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;


public class CglibProxy implements MethodInterceptor {
	private Object targetObject;
	// 这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理
	public Object getInstance(Object target) {
		// 设置需要创建子类的类
		this.targetObject = target;
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(target.getClass());
		enhancer.setCallback(this);
		return enhancer.create();
	}

	//代理实际方法
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("开启事物");
		Object result = proxy.invoke(targetObject, args);
		System.out.println("关闭事物");
		// 返回代理对象
		return result;
	}
}

4)测试CGLIB动态代理,具体代码如下:

package com.yoodb.blog;

public class Test {
    public static void main(String[] args) {
        CglibProxy cglibProxy = new CglibProxy();
        UserDao userDao = (UserDao) cglibProxy.getInstance(new UserDaoImpl());
        userDao.save();
    }
}

题5:Java 中装饰模式有什么优缺点?

装饰模式优点

1、装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态决定“贴上”一个需要的“装饰”,或者除掉一个不需要的“装饰”。继承关系则不同,继承关系是静态的,它在系统运行前就决定了。

2、通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

装饰模式缺点

由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。

题6:Java 中什么是解释器模式?

解释器模式是类的行为模式。给定一个语言之后,解释器模式可以定义出其文法的一种表示,并同时提供一个解释器。客户端可以使用这个解释器来解释这个语言中的句子。

该模式涉及角色如下:

1)抽象表达式(Expression)角色:声明一个所有的具体表达式角色都需要实现的抽象接口。这个接口主要是一个interpret()方法,称做解释操作。

2)终结符表达式(Terminal Expression)角色:实现了抽象表达式角色所要求的接口,主要是一个interpret()方法;文法中的每一个终结符都有一个具体终结表达式与之相对应。比如有一个简单的公式R=R1+R2,在里面R1和R2就是终结符,对应的解析R1和R2的解释器就是终结符表达式。

3)非终结符表达式(Nonterminal Expression)角色:文法中的每一条规则都需要一个具体的非终结符表达式,非终结符表达式一般是文法中的运算符或者其他关键字,比如公式R=R1+R2中,“+"就是非终结符,解析“+”的解释器就是一个非终结符表达式。

4)环境(Context)角色:这个角色的任务一般是用来存放文法中各个终结符所对应的具体值,比如R=R1+R2,我们给R1赋值100,给R2赋值200。这些信息需要存放到环境角色中,很多情况下我们使用Map来充当环境角色就足够了。

题7:Java 中如何实现解释器模式?

Java中实现解释器模式,说一说演示代码。

1、实体类Context,具体代码如下:

package com.yoodb;
 
public class Context {
    private Integer numo;
     
    private Integer numt;
     
 
    public Context(Integer numo, Integer numt) {
        this.numo = numo;
        this.numt = numt;
    }
 
    public Integer getNumo() {
        return numo;
    }
 
    public void setNumo(Integer numo) {
        this.numo = numo;
    }
 
    public Integer getNumt() {
        return numt;
    }
 
    public void setNumt(Integer numt) {
        this.numt = numt;
    }
     
}

2、一个接口,具体代码如下:

package com.yoodb;
 
public interface Expression {
    public int interpret(Context context);
}

3、两个接口实现类,一个类是参数相加,一个类是参数相减,具体代码如下:

package com.yoodb;
 
public class Minus implements Expression {
 
    @Override
    public int interpret(Context context) {
        // TODO Auto-generated method stub
         return context.getNumo()-context.getNumt();  
    }
 
}
package com.yoodb;
 
 
public class Plus implements Expression {
 
    @Override
    public int interpret(Context context) {
        // TODO Auto-generated method stub
        return context.getNumo() + context.getNumt();  
    }
 
}

4、单元测试,具体代码如下:

package com.yoodb;
 
public class MainTest {
    public static void main(String[] args) {
        int result = new Minus().interpret((new Context(new Plus().interpret(new Context(2015, 8)), 4))); 
        System.out.println(result);
    }
}

运行结果如下:

2019

题8:Java 中代理模式如何实现动态代理?

Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:

1)Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组;这个抽象方法在代理类中动态实现。

2)Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容:

Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。

Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。

接口(或抽象类),具体代码如下:

package com.yoodb;
 
public interface Business {
    public void doAction();
}

此处是真正意义上实现业务逻辑的类,具体代码如下:

package com.yoodb;
 
public class BusinessImpl implements Business {
 
    @Override
    public void doAction() {
        // TODO Auto-generated method stub
        System.out.println("实现业务逻辑.");
    }
 
}

动态代理方式,具体代码如下:

package com.yoodb;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
 
public class DynamicBusinessProxy implements InvocationHandler{
     
    private Object obj;
     
    public DynamicBusinessProxy() {}
     
    public DynamicBusinessProxy(Object obj) {
        this.obj = obj;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // TODO Auto-generated method stub
        Object result = null;
        doBefore();
        result = method.invoke(obj, args);
        doAfter();     
        return result;
    }
 
    private void doBefore(){  
System.out.println("调用目标对象前做相关操作");  
    }  
     
    private void doAfter(){  
System.out.println("调用目标对象后做相关操作");  
    }
     
    public static Object factory(Object obj)  
    {  
Class<? extends Object> cls = obj.getClass();
return Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),new DynamicBusinessProxy(obj));  
    } 
}

单元测试,具体代码如下:

package com.yoodb;
 
public class MainTest {
    public static void main(String[] args) {
        Business business = (Business) DynamicBusinessProxy.factory(new BusinessImpl());
        business.doAction();
    }
}

运行之后结果如下:

调用目标对象前做相关操作
实现业务逻辑.
调用目标对象后做相关操作

题9:Java 中什么是原型模式?

原型模式是一种创建型设计模式,通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的对象。

原型设计模式简单来说就是克隆,原型模式多用于创建复杂的或者构造耗时的实例,因为这种情况下,复制一个已经存在的实例可使程序运行更高效。

原型模式有两种表现形式:

1)简单形式;

2)登记形式,这两种表现形式仅仅是原型模式的不同实现。

简单形式的原型模式,涉及到三种角色分别如下:

1)客户(Client)角色:客户类提出创建对象的请求。

2)抽象原型(Prototype)角色:这是一个抽象角色,通常由一个Java接口或Java抽象类实现。此角色给出所有的具体原型类所需的接口。

3)具体原型(Concrete Prototype)角色:被复制的对象。此角色需要实现抽象的原型角色所要求的接口。

题10:Java 中单例模式如何防止反射漏洞攻击?

public class Singleton {
	private static boolean flag = false;

	private Singleton() {

		if (flag == false) {
			flag = !flag;
		} else {
			throw new RuntimeException("关注Java精选公众号,提醒单例模式被攻击!");
		}
	}

	public static void main(String[] args) {

	}
}

题11:单例模式都有哪些应用场景

题12:java-中什么是外观模式

题13:java-中原型模式有哪些使用方式

题14:什么是代理模式

题15:java-中如何实现建造者模式

题16:为什么要使用设计模式

题17:java-中代理模式有什么应用场景

题18:java-中实现观察者模式有哪两种方式

题19:java-中什么是适配器模式

题20:java-中如何实现策略模式

题21:java-中原型模式如何实现深拷贝

题22:java-中什么是替换法则lsp

题23:java-中如何实现装饰模式

题24:微服务架构的六种常用设计模式是什么

题25:装饰模式和适配器模式有什么区别

大厂面试题

大厂面试题

大厂面试题

Java
1
https://gitee.com/huo-yuelong/ebooks.git
git@gitee.com:huo-yuelong/ebooks.git
huo-yuelong
ebooks
Ebooks
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891