一、创建型模式
1. 单例模式
作用:全局只有一个实例,统一入口、节约资源。
适用场景:配置类、工具类、连接池管理器。
常见写法:饿汉、懒汉、双重校验锁 DCL、枚举单例。
(1) 饿汉式(线程安全、最简单)
类加载时直接初始化,天然线程安全。
优点:简单、无锁、线程安全
缺点:类加载就创建,不用也占内存。
(双重校验、静态内部类)
java
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
(2) 懒汉式(非线程安全,不推荐)
用到才创建,多线程会造出多个实例。
java
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
(3) 加锁懒汉式(效率低)
java
public static synchronized Singleton getInstance(){}
缺点:每次获取都加锁,并发性能差
(4) 双重校验锁 DCL(面试重点)
java
public class Singleton {
// volatile 禁止指令重排
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 作用: 防止 new 对象 指令重排导致半初始化对象被其他线程拿到。
(5) 枚举单例(最佳写法)
java
public enum Singleton {
INSTANCE;
// 业务方法
}
PS:为什么枚举是最优?
- 写法极简
- 天生线程安全
- 防止反射暴力创建
- 防止序列化 / 反序列化破坏单例
2. 工厂模式
核心思想:屏蔽 new 创建对象细节,统一由工厂负责创建,调用方只管用,不用管怎么造。
优点:
- 对象创建和使用解耦
- 统一管理创建逻辑
- 便于扩展、替换产品
(1) 简单工厂(静态工厂)
java
// **************** 产品抽象接口 ********************
public interface Pay {
void pay();
}
// ***************** 多个具体产品 *****************
class AliPay implements Pay{
public void pay() { System.out.println("支付宝支付"); }
}
class WechatPay implements Pay{
public void pay() { System.out.println("微信支付"); }
}
// ************** 简单工厂,统一生产 ******************
public class PayFactory {
public static Pay createPay(String type){
if("ali".equals(type)){
return new AliPay();
}else if("wechat".equals(type)){
return new WechatPay();
}
return null;
}
}
- 优点:简单、上手快
- 缺点:加新产品要改工厂代码,违反开闭原则
- 本质:一个工厂造所有产品
(2) 工厂方法模式(标准工厂)
java
// ****************** 支付产品抽象 ****************
public interface Payment {
void pay();
}
// ***************** 支付宝支付 **************
public class AliPayment implements Payment {
@Override
public void pay() {
System.out.println("使用支付宝支付");
}
}
// 微信支付
public class WechatPayment implements Payment {
@Override
public void pay() {
System.out.println("使用微信支付");
}
}
// *************** 抽象工厂 ***************
public interface PaymentFactory {
Payment createPayment();
}
// *************** 支付宝工厂 ****************
public class AliPaymentFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new AliPayment();
}
}
// 微信工厂
public class WechatPaymentFactory implements PaymentFactory {
@Override
public Payment createPayment() {
return new WechatPayment();
}
}
(3) 抽象工厂模式(基本不用)
java
// ************** 抽象产品:手机 ******************
public interface Phone {
void call();
}
// *************** 具体产品1:小米手机 ****************
public class XiaomiPhone implements Phone {
@Override
public void call() {
System.out.println("小米手机 打电话");
}
}
// 具体产品1:华为手机
public class HuaweiPhone implements Phone {
@Override
public void call() {
System.out.println("华为手机 打电话");
}
}
// ***************************************************
// 抽象产品:笔记本
public interface Laptop {
void work();
}
// 具体产品2:小米笔记本
public class XiaomiLaptop implements Laptop {
@Override
public void work() {
System.out.println("小米笔记本 办公");
}
}
// 具体产品2:华为笔记本
public class HuaweiLaptop implements Laptop {
@Override
public void work() {
System.out.println("华为笔记本 办公");
}
// ***************** 抽象工厂:手机+笔记本 **************
public interface AbstractFactory {
Phone createPhone();
Laptop createLaptop();
}
// ********************* 具体工厂 ********************
public class XiaomiFactory implements AbstractFactory {
@Override
public Phone createPhone() {
return new XiaomiPhone();
}
@Override
public Laptop createLaptop() {
return new XiaomiLaptop();
}
}
(4) 三种工厂对比
| 模式 | 核心 | 开闭原则 | 适用场景 |
| 简单工厂 | 一个工厂造所有产品 | 违反 | 产品固定、不常扩展 |
| 工厂方法 | 一个工厂造一个产品 | 符合 | 频繁加新业务类型 |
| 抽象工厂 | 一个工厂造一族产品 | 产品族难扩展 | 多品牌成套产品 |
|---|
二、结构型模式
1. 适配器模式
作用:适配接口不兼容,做转换兼容。
场景:老系统适配、第三方接口适配、电压转换。
适用:
- 老系统接口和新系统接口不兼容
- 接入第三方 SDK、接口格式不一样
- 复用现有类,但接口不符合当前规范
- 不想修改原有源码,做兼容适配
两类实现:
- 类适配器:继承被适配者 + 实现目标接口(Java 单继承,用得少)
- 对象适配器 :组合持有被适配者,开发常用、推荐。
(1) 对象适配器
java
// **************** 目标接口:国标充电 ******************
public interface ChinaCharge {
void charge();
}
// ************** 被适配接口:苹果充电器(原有/第三方,接口不匹配)*************
public class AppleCharge {
public void appleConnect() {
System.out.println("苹果充电器 通电");
}
}
// ****************** 适配器:把苹果适配成国标 *******************
public class ChargeAdapter implements ChinaCharge {
// 组合持有被适配者
private AppleCharge appleCharge;
public ChargeAdapter(AppleCharge appleCharge) {
this.appleCharge = appleCharge;
}
@Override
public void charge() {
// 调用老接口,做适配转换
appleCharge.appleConnect();
System.out.println("通过适配器转为国标充电");
}
}
// ****************** 客户端使用 *****************
public class Client {
public static void main(String[] args) {
AppleCharge apple = new AppleCharge();
ChinaCharge adapter = new ChargeAdapter(apple);
adapter.charge();
}
}
适配器 vs 装饰器 区别(面试常问)
-
适配器 :接口不兼容,做转换,改接口规范
-
装饰器 :接口完全一样,加功能,不改接口只增强逻辑
2. 装饰器模式
作用:不改原类,动态给对象加功能。
场景:IO 流包装、业务功能叠加(基础服务 + 增强)。
适用:
- Java IO 流包装(BufferedReader 包装 Reader)
- 动态给类叠加功能,不用继承扩展
- 业务功能层层增强:基础服务 + 日志 + 权限 + 限流
- 避免子类爆炸(不用每种组合都写一个子类)
java
// **************** 抽象构件接口: 奶茶 ******************
public interface MilkTea {
String getDesc();
double getPrice();
}
// ***************** 具体构件:基础原味奶茶 ******************
public class OriginalMilkTea implements MilkTea {
@Override
public String getDesc() {
return "原味奶茶";
}
@Override
public double getPrice() {
return 10.0;
}
}
// **************** 抽象装饰器:和被装饰者实现同一个接口 ******************
public abstract class MilkTeaDecorator implements MilkTea {
protected MilkTea milkTea;
public MilkTeaDecorator(MilkTea milkTea) {
this.milkTea = milkTea;
}
}
// ******************** 具体装饰器 ***********************
public class PearlDecorator extends MilkTeaDecorator {
public PearlDecorator(MilkTea milkTea) {
super(milkTea);
}
@Override
public String getDesc() {
return milkTea.getDesc() + " + 珍珠";
}
@Override
public double getPrice() {
return milkTea.getPrice() + 2.0;
}
}
3. 代理模式
作用:控制对真实对象的访问,加前置 / 后置逻辑。
分类:静态代理、JDK 动态代理、CGLIB 代理。
场景:Spring AOP、事务、权限拦截、日志埋点。
(1) 静态代理
缺点 :每代理一个类,就要手写一个代理类,类爆炸,扩展性差。
java
// ******************* 抽象接口 *******************
public interface UserService {
void addUser();
}
// ******************* 真实对象 *******************
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("新增用户业务逻辑");
}
}
// ******************* 代理类 ********************
public class UserProxy implements UserService {
private UserService target;
public UserProxy(UserService target) {
this.target = target;
}
@Override
public void addUser() {
System.out.println("前置:权限校验/日志");
target.addUser();
System.out.println("后置:记录操作日志");
}
}
// ********************** 调用 *******************
public class Test {
public static void main(String[] args) {
UserService target = new UserServiceImpl();
UserService proxy = new UserProxy(target);
proxy.addUser();
}
}
(2) JDK动态代理
特点:
- 必须有接口
- 基于接口生成代理类
InvocationHandler回调
java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 处理器
public class JdkProxyHandler implements InvocationHandler {
private Object target;
public JdkProxyHandler(Object target) {
this.target = target;
}
// 生成代理对象
public Object getProxy() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK代理 前置增强");
Object result = method.invoke(target, args);
System.out.println("JDK代理 后置增强");
return result;
}
}
(3) CGLIB动态代理
特点:
- 不需要接口
- 通过继承目标类生成子类做代理
- 不能代理
final类和final方法
原理:ASM 字节码生成子类,重写方法做增强。
三、行为型模式
1. 策略模式
作用:同一行为多种算法,可自由切换。
场景:支付方式(微信 / 支付宝 / 银行卡)、运费计算、折扣算法。
java
// ******************** 策略接口 **********************
// 支付策略接口
public interface PayStrategy {
void pay(double money);
}
// ******************** 具体策略实现 ***********************
// 支付宝策略
public class AliPayStrategy implements PayStrategy {
@Override
public void pay(double money) {
System.out.println("支付宝支付:" + money + " 元");
}
}
// 微信支付策略
public class WechatPayStrategy implements PayStrategy {
@Override
public void pay(double money) {
System.out.println("微信支付:" + money + " 元");
}
}
// ******** 上下文环境(统一入口) ********
public class PayContext {
// 持有策略
private PayStrategy strategy;
// 注入策略
public PayContext(PayStrategy strategy) {
this.strategy = strategy;
}
// 可动态切换策略
public void setStrategy(PayStrategy strategy) {
this.strategy = strategy;
}
// 统一执行
public void executePay(double money) {
strategy.pay(money);
}
}
// ***************** 客户端调用 ********************
public class Client {
public static void main(String[] args) {
// 用支付宝
PayContext context = new PayContext(new AliPayStrategy());
context.executePay(99.9);
// 切换成微信
context.setStrategy(new WechatPayStrategy());
context.executePay(59.9);
}
}
2. 模板方法模式
作用:父类定骨架,子类实现可变步骤。
场景:Spring 初始化流程、统一业务流程模板。
java
// ******************** 抽象模板 ******************
public abstract class BusinessTemplate {
// 模板方法:固定整体流程,final禁止重写
public final void execute() {
before();
doBusiness();
after();
}
// 固定前置步骤
private void before() {
System.out.println("通用前置:参数校验、日志记录");
}
// 可变业务步骤:由子类实现
protected abstract void doBusiness();
// 固定后置步骤
private void after() {
System.out.println("通用后置:结果归档、统一返回");
}
}
// ********************** 具体子类 *********************
public class OrderBusiness extends BusinessTemplate {
@Override
protected void doBusiness() {
System.out.println("订单业务:创建订单、扣库存");
}
}
// ********* 客户端调用 ********
public class Client {
public static void main(String[] args) {
BusinessTemplate order = new OrderBusiness();
order.execute();
System.out.println("------");
BusinessTemplate pay = new PayBusiness();
pay.execute();
}
}
3. 观察者模式
作用:一对多发布订阅,状态变化自动通知所有订阅者。
场景:消息通知、事件监听、MQ 消费、Spring 事件机制。
两种模式区分:
- 传统观察者:同步、进程内、代码耦合。
- MQ 发布订阅:异步、跨服务、解耦更强,本质思想就是观察者模式。
java
// **************** 抽象观察者 *******************
public interface Observer {
// 收到通知更新自己
void update(String message);
}
// **************** 具体观察者 ***************
// 用户A
public class UserObserverA implements Observer {
@Override
public void update(String message) {
System.out.println("用户A 收到消息:" + message);
}
}
// 用户B
public class UserObserverB implements Observer {
@Override
public void update(String message) {
System.out.println("用户B 收到消息:" + message);
}
}
// ***************** 抽象被观察者 *****************
public abstract class Subject {
// 保存所有观察者
protected List<Observer> observerList = new ArrayList<>();
// 订阅
public void addObserver(Observer o) {
observerList.add(o);
}
// 取消订阅
public void removeObserver(Observer o) {
observerList.remove(o);
}
// 通知所有观察者
public abstract void notifyObservers(String msg);
}
// ***************** 具体被观察者 *******************
public class OfficialSubject extends Subject {
@Override
public void notifyObservers(String msg) {
for (Observer o : observerList) {
o.update(msg);
}
}
// 发布文章,触发推送
public void publishArticle(String content) {
System.out.println("公众号发布新文章:" + content);
notifyObservers(content);
}
}
// ********** 客户端测试 *********
public class Client {
public static void main(String[] args) {
// 被观察者
OfficialSubject subject = new OfficialSubject();
// 观察者订阅
subject.addObserver(new UserObserverA());
subject.addObserver(new UserObserverB());
// 发布消息,自动推给所有人
subject.publishArticle("Java设计模式干货更新");
}
}
4. 责任链模式
作用:请求沿链条依次处理,每个节点可处理 / 放行 / 终止。
场景:拦截器、过滤器、权限校验链、审批流程。
java
// 请求类
public class LeaveRequest {
private String name;
private int days;
// 构造、getter
public LeaveRequest(String name, int days) {
this.name = name;
this.days = days;
}
public int getDays() { return days; }
public String getName() { return name; }
}
// ******************** 抽象处理器 **********************
public abstract class Approver {
protected Approver next; // 下一个处理者
public void setNext(Approver next) {
this.next = next;
}
public abstract void approve(LeaveRequest req);
}
// ********************* 具体处理器 *********************
// 组长:≤3天
public class TeamLeader extends Approver {
@Override
public void approve(LeaveRequest req) {
if (req.getDays() <= 3) {
System.out.println("组长批了:" + req.getName() + " " + req.getDays() + "天");
} else if (next != null) {
next.approve(req);
}
}
}
// 经理:≤7天
public class Manager extends Approver {
@Override
public void approve(LeaveRequest req) {
if (req.getDays() <= 7) {
System.out.println("经理批了:" + req.getName() + " " + req.getDays() + "天");
} else if (next != null) {
next.approve(req);
}
}
}
// 总监:≤30天
public class Director extends Approver {
@Override
public void approve(LeaveRequest req) {
if (req.getDays() <= 30) {
System.out.println("总监批了:" + req.getName() + " " + req.getDays() + "天");
} else {
System.out.println("太长了,不批");
}
}
}
// ******************** 客户端(组装链) **********************
public class Client {
public static void main(String[] args) {
Approver leader = new TeamLeader();
Approver manager = new Manager();
Approver director = new Director();
// 链:组长 → 经理 → 总监
leader.setNext(manager);
manager.setNext(director);
leader.approve(new LeaveRequest("张三", 2)); // 组长
leader.approve(new LeaveRequest("李四", 5)); // 经理
leader.approve(new LeaveRequest("王五", 20)); // 总监
leader.approve(new LeaveRequest("赵六", 40)); // 不批
}
}