Java面试-07-设计模式

Java 设计模式面试题(完整版·可直接背诵)

目录

  • [1. 设计模式三大分类](#1. 设计模式三大分类)
  • [2. 单例模式](#2. 单例模式)
  • [3. 工厂模式 / 抽象工厂模式](#3. 工厂模式 / 抽象工厂模式)
  • [4. 代理模式(静态+JDK+CGLib)](#4. 代理模式(静态+JDK+CGLib))

1. 设计模式三大分类

创建型(5种)

对象怎么创建

工厂方法、抽象工厂、单例、建造者、原型

结构型(7种)

类/对象怎么组合

适配器、装饰器、代理、外观、桥接、组合、享元

行为型(11种)

对象之间怎么通信

策略、模板方法、观察者、迭代器、责任链、命令、备忘录、状态、访问者、中介者、解释器


2. 单例模式

定义

确保一个类全局只有一个实例,自己实例化,对外提供统一访问点。

适用场景

线程池、缓存、日志对象、配置加载、打印机、驱动、连接池。

特点

  • 只有一个实例
  • 构造器私有
  • 自行实例化
  • 全局访问

四大原则

  1. 构造方法私有
  2. 静态方法返回实例
  3. 多线程安全
  4. 反序列化不重建对象

实现方式(高频面试)

① 饿汉式(静态常量)

类加载就创建,天生线程安全

java 复制代码
public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() { return INSTANCE; }
}

优点:简单、线程安全

缺点:可能浪费内存

② 饿汉式(静态代码块)

java 复制代码
public class Singleton {
    private static Singleton INSTANCE;
    static { INSTANCE = new Singleton(); }
    private Singleton() {}
    public static Singleton getInstance() { return INSTANCE; }
}

③ 懒汉式(线程不安全)

用到才创建,但多线程不安全。

④ 双重检查锁 DCL(推荐)

java 复制代码
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;
    }
}

关键点:volatile 禁止指令重排

⑤ 静态内部类(最优)

java 复制代码
public class Singleton {
    private Singleton() {}
    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

⑥ 枚举单例(最安全)

java 复制代码
public enum Singleton {
    INSTANCE;
}

优点:防反射、防反序列化、天生线程安全


3. 工厂模式 / 抽象工厂模式

工厂方法模式

一个工厂生产一种产品

结构

  • 抽象产品(Fruit)
  • 具体产品(Apple、Pear)
  • 抽象工厂(FruitFactory)
  • 具体工厂(AppleFactory、PearFactory)

优点

  • 解耦:创建与使用分离
  • 符合开闭原则

缺点

产品多 → 工厂类爆炸


抽象工厂模式

一个工厂生产一系列相关产品(产品族)。

示例:手机工厂 → 生产 CPU + 屏幕

结构

  • 抽象产品族:CPU、Screen
  • 具体产品:Cpu650/Cpu825、Screen5/Screen6
  • 抽象工厂:PhoneFactory
  • 具体工厂:XiaoMiFactory、HongMiFactory

优点

  • 统一管理系列产品
  • 保证产品兼容性
  • 一定程度符合开闭

缺点

增加新产品 → 要改所有工厂(违反开闭)


三种工厂总结

  • 简单工厂:产品固定、少
  • 工厂方法:单一产品、可扩展
  • 抽象工厂:产品族、系列化

4. 代理模式(静态+JDK+CGLib)

定义

为对象提供代理对象 ,控制原对象访问。

作用:中介、增强、隔离、日志、事务、权限。

分类

  • 静态代理
  • 动态代理(JDK、CGLib)

静态代理

编译期就生成代理类

java 复制代码
public interface BuyHouse { void buyHouse(); }

public class BuyHouseImpl implements BuyHouse {
    public void buyHouse() { System.out.println("买房"); }
}

public class BuyHouseProxy implements BuyHouse {
    private BuyHouse target;
    public BuyHouseProxy(BuyHouse target) { this.target = target; }

    public void buyHouse() {
        System.out.println("前");
        target.buyHouse();
        System.out.println("后");
    }
}

优点:简单

缺点:每个接口都要写代理类,维护爆炸


JDK 动态代理

基于接口

java 复制代码
public class DynamicProxyHandler implements InvocationHandler {
    private Object target;
    public DynamicProxyHandler(Object target) { this.target = target; }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前");
        Object res = method.invoke(target, args);
        System.out.println("后");
        return res;
    }
}

// 使用
BuyHouse proxy = (BuyHouse) Proxy.newProxyInstance(
    classLoader,
    new Class[]{BuyHouse.class},
    new DynamicProxyHandler(real)
);

优点:不用写代理类

缺点:必须有接口


CGLib 动态代理

基于继承 ,生成子类代理

无需接口。

java 复制代码
public class CglibProxy implements MethodInterceptor {
    private Object target;
    public CglibProxy(Object target) { this.target = target; }

    public Object intercept(Object o, Method m, Object[] args, MethodProxy mp) throws Throwable {
        System.out.println("前");
        Object res = mp.invokeSuper(o, args);
        System.out.println("后");
        return res;
    }
}

优点:无接口也能代理

缺点:不能代理 final 类/final 方法


三种代理对比

代理 原理 要求 适用
静态代理 编码实现 接口 简单、少量
JDK动态代理 接口+反射 必须接口 Spring AOP 默认
CGLib 继承+字节码 无接口 类无接口