常用设计模式

一、创建型模式

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)); // 不批
    }
}
相关推荐
前端不太难1 小时前
AI Native 鸿蒙 App 的四层架构
人工智能·架构·harmonyos
likerhood1 小时前
设计模式 · 组合模式(Composite Pattern)
设计模式·组合模式
xixingzhe21 小时前
灰度发布注意点
架构
薛定猫AI1 小时前
【深度解析】Codex 集成 Ollama:在本地开源大模型上构建 AI 编程工作流
人工智能·安全·架构
多加点辣也没关系1 小时前
设计模式-迭代器模式
设计模式·迭代器模式
许长安1 小时前
Kafka 架构讲解:从提交日志到分区副本机制
c++·经验分享·笔记·分布式·架构·kafka
uzong2 小时前
这套AI技术栈可将你的人工智能成本削减80%
人工智能·后端·架构
Lee川2 小时前
个人中心与 AI 头像生成:从页面到 DALL-E 的完整实现
前端·架构
薛定猫AI4 小时前
【深度解析】终端里的免费 AI 编程助手 Freebuff:多代理架构、模型路由与安全使用实战
人工智能·安全·架构