吃透设计模式+面试:原理、场景、代码三位一体,系统梳理核心知识点

前言

还在为设计模式面试抓瞎?这篇直接给你划重点!涵盖创建型、结构型、行为型三大类共 20 道高频题,从单例模式线程安全实现,到工厂、代理、观察者等核心模式的原理、场景、区别全拆解。

一、创建型设计模式

1. 什么是单例模式?请实现一个线程安全的单例模式。

单例模式确保一个类仅有一个实例,并提供一个全局访问点。线程安全的单例需避免多线程同时创建实例,常见实现方式有饿汉式、懒汉式(双重检查锁定)、静态内部类等。其中,双重检查锁定通过两次判断实例是否为空,并使用synchronized同步示例,既保证线程安全又提高效率。

示例

java 复制代码
public class Singleton {
    //  volatile防止指令重排序,确保instance初始化完成后再被访问
    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;
    }
}

2. 工厂模式有哪几种?简单工厂模式与工厂方法模式的区别是什么?

工厂模式分为简单工厂模式、工厂方法模式、抽象工厂模式。

  • 简单工厂模式:由一个工厂类根据传入的参数决定创建哪种产品实例,违背"开闭原则"(新增产品需修改工厂类)。
  • 工厂方法模式:定义一个创建产品的接口,由子类决定具体创建哪种产品,每个产品对应一个工厂子类,符合"开闭原则"(新增产品只需新增工厂子类)。

示例

java 复制代码
// 产品接口
interface Product { void produce(); }
// 具体产品A
class ProductA implements Product { public void produce() { System.out.println("生产A"); } }
// 具体产品B
class ProductB implements Product { public void produce() { System.out.println("生产B"); } }
// 简单工厂
class SimpleFactory {
    public static Product createProduct(String type) {
        if ("A".equals(type)) return new ProductA();
        else if ("B".equals(type)) return new ProductB();
        else throw new IllegalArgumentException("无效类型");
    }
}
java 复制代码
// 产品接口(同上)
interface Product { void produce(); }
// 具体产品A、B(同上)
// 工厂接口
interface Factory { Product createProduct(); }
// 产品A的工厂
class FactoryA implements Factory { public Product createProduct() { return new ProductA(); } }
// 产品B的工厂
class FactoryB implements Factory { public Product createProduct() { return new ProductB(); } }

3. 抽象工厂模式的适用场景是什么?请举例说明。

抽象工厂模式提供一个接口,用于创建一系列相关或相互依赖的对象,而无需指定具体类。适用于产品族(多个相关产品组成的集合)的创建,当需要保证产品间的兼容性时使用。

例如,电脑厂商需同时生产CPU和主板,不同品牌(如Intel、AMD)的CPU和主板需配套使用,抽象工厂可确保创建的CPU和主板属于同一品牌。

示例

java 复制代码
// 产品接口:CPU
interface CPU { void calculate(); }
// 产品接口:主板
interface Mainboard { void installCPU(); }

// 具体产品:Intel CPU
class IntelCPU implements CPU { public void calculate() { System.out.println("Intel CPU计算"); } }
// 具体产品:Intel主板
class IntelMainboard implements Mainboard { public void installCPU() { System.out.println("安装Intel CPU"); } }

// 具体产品:AMD CPU
class AmdCPU implements CPU { public void calculate() { System.out.println("AMD CPU计算"); } }
// 具体产品:AMD主板
class AmdMainboard implements Mainboard { public void installCPU() { System.out.println("安装AMD CPU"); } }

// 抽象工厂接口
interface ComputerFactory {
    CPU createCPU();
    Mainboard createMainboard();
}

// Intel工厂(生产Intel产品族)
class IntelFactory implements ComputerFactory {
    public CPU createCPU() { return new IntelCPU(); }
    public Mainboard createMainboard() { return new IntelMainboard(); }
}

// AMD工厂(生产AMD产品族)
class AmdFactory implements ComputerFactory {
    public CPU createCPU() { return new AmdCPU(); }
    public Mainboard createMainboard() { return new AmdMainboard(); }
}

4. 建造者模式与工厂模式的区别是什么?

  • 工厂模式专注于"创建什么",主要用于创建单一产品,隐藏产品的创建过程,客户端只需知道产品类型即可。
  • 建造者模式专注于"如何创建",用于创建复杂对象(由多个部分组成),通过分步构建并组装各部分,客户端可控制构建过程,且能灵活改变产品的内部结构。
    例如,工厂模式可直接创建"电脑",而建造者模式可分步构建"电脑的CPU、内存、硬盘"并组装成电脑。

示例

java 复制代码
// 产品:电脑
class Computer {
    private String cpu;
    private String memory;
    // 省略getter、setter和toString
}

// 建造者接口
interface ComputerBuilder {
    void buildCPU();
    void buildMemory();
    Computer getResult();
}

// 具体建造者:游戏电脑
class GameComputerBuilder implements ComputerBuilder {
    private Computer computer = new Computer();
    public void buildCPU() { computer.setCpu("高性能CPU"); }
    public void buildMemory() { computer.setMemory("32G内存"); }
    public Computer getResult() { return computer; }
}

// 指挥者:控制构建流程
class Director {
    public Computer construct(ComputerBuilder builder) {
        builder.buildCPU();
        builder.buildMemory();
        return builder.getResult();
    }
}

5. 原型模式的核心是什么?深拷贝与浅拷贝的区别?

原型模式通过复制现有实例(原型)来创建新实例,核心是clone()方法,避免重复初始化对象,提高创建效率。

  • 浅拷贝:仅复制对象本身及基本类型字段,引用类型字段仍指向原对象的引用(修改拷贝对象的引用字段会影响原对象)。
  • 深拷贝:复制对象本身及所有引用类型字段(递归拷贝),原对象与拷贝对象完全独立(修改互不影响)。

示例

java 复制代码
import java.io.*;

// 实现Cloneable接口(浅拷贝)
class Prototype implements Cloneable, Serializable {
    private String name;
    private ReferenceType ref; // 引用类型字段

    // 浅拷贝
    @Override
    protected Prototype clone() throws CloneNotSupportedException {
        return (Prototype) super.clone();
    }

    // 深拷贝(通过序列化实现)
    public Prototype deepClone() throws IOException, ClassNotFoundException {
        // 序列化
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(this);
        // 反序列化
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (Prototype) ois.readObject();
    }
}

class ReferenceType implements Serializable {
    private int value;
    // 省略getter、setter
}

二、结构型设计模式

6. 适配器模式有哪两种实现方式?请举例说明类适配器。

适配器模式将一个类的接口转换成客户端期望的另一个接口,使不兼容的类可以一起工作。分为类适配器(通过继承实现)和对象适配器(通过组合实现)。类适配器通过继承适配者类并实现目标接口,缺点是受单继承限制;对象适配器通过持有适配者实例实现,更灵活。

示例(类适配器):

java 复制代码
// 目标接口(客户端期望的接口)
interface Target { void request(); }

// 适配者(需要被适配的类)
class Adaptee {
    public void specificRequest() { System.out.println("适配者的特殊请求"); }
}

// 类适配器(继承Adaptee,实现Target)
class ClassAdapter extends Adaptee implements Target {
    public void request() {
        // 调用适配者的方法,适配成目标接口
        specificRequest();
    }
}

7. 装饰器模式的作用是什么?与继承相比有何优势?

装饰器模式动态地给对象添加额外职责,不改变其原有结构。优势在于:

  • 比继承更灵活:可动态组合多个装饰器,而继承是静态的,且可能导致类爆炸(每增加一个功能需新增子类)。
  • 遵循"开闭原则":新增功能只需新增装饰器类,无需修改原有代码。
    例如,给咖啡加牛奶、加糖,可通过MilkDecoratorSugarDecorator动态装饰Coffee对象。

示例

java 复制代码
// 抽象组件:咖啡
abstract class Coffee {
    abstract String getDescription();
    abstract double cost();
}

// 具体组件:黑咖啡
class BlackCoffee extends Coffee {
    public String getDescription() { return "黑咖啡"; }
    public double cost() { return 10; }
}

// 装饰器抽象类(继承Coffee,持有Coffee实例)
abstract class CoffeeDecorator extends Coffee {
    protected Coffee coffee;
    public CoffeeDecorator(Coffee coffee) { this.coffee = coffee; }
}

// 具体装饰器:牛奶
class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) { super(coffee); }
    public String getDescription() { return coffee.getDescription() + "+牛奶"; }
    public double cost() { return coffee.cost() + 3; }
}

// 具体装饰器:糖
class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) { super(coffee); }
    public String getDescription() { return coffee.getDescription() + "+糖"; }
    public double cost() { return coffee.cost() + 2; }
}

// 使用:黑咖啡+牛奶+糖
public class Test {
    public static void main(String[] args) {
        Coffee coffee = new BlackCoffee();
        coffee = new MilkDecorator(coffee);
        coffee = new SugarDecorator(coffee); 
        System.out.println(coffee.getDescription() + ",价格:" + coffee.cost());
    }
}

8. 代理模式有哪几种?静态代理与动态代理的区别?

代理模式为对象提供一个代理,控制对原对象的访问。分为静态代理、动态代理(JDK动态代理、CGLIB动态代理)。

  • 静态代理:代理类在编译期生成,与目标类实现同一接口,缺点是每代理一个类需手动编写代理类,复用性差。
  • 动态代理:代理类在运行期动态生成,无需手动编写,JDK动态代理基于接口(目标类需实现接口),CGLIB基于继承(目标类可无接口)。

示例

java 复制代码
// 接口
interface UserService { void save(); }
// 目标类
class UserServiceImpl implements UserService { public void save() { System.out.println("保存用户"); } }
// 静态代理类
class UserServiceProxy implements UserService {
    private UserService target;
    public UserServiceProxy(UserService target) { this.target = target; }
    public void save() {
        System.out.println("前置日志"); // 增强
        target.save();
        System.out.println("后置日志"); // 增强
    }
}
java 复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// InvocationHandler实现类
class LogHandler implements InvocationHandler {
    private Object target;
    public LogHandler(Object target) { this.target = target; }
    // 动态生成代理方法
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前置日志");
        Object result = method.invoke(target, args);
        System.out.println("后置日志");
        return result;
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        UserService target = new UserServiceImpl();
        // 生成代理对象
        UserService proxy = (UserService) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new LogHandler(target)
        );
        proxy.save();
    }
}

9. 外观模式(Facade)的作用是什么?请举例说明。

外观模式为子系统中的一组接口提供一个统一的高层接口,简化客户端与子系统的交互。例如,电脑启动需依次启动CPU、内存、硬盘等子系统,外观模式可提供一个ComputerFacade类,封装这些子系统的启动逻辑,客户端只需调用start()即可。

示例

java 复制代码
// 子系统1:CPU
class CPU { public void start() { System.out.println("CPU启动"); } }
// 子系统2:内存
class Memory { public void start() { System.out.println("内存启动"); } }
// 外观类
class ComputerFacade {
    private CPU cpu;
    private Memory memory;
    public ComputerFacade() {
        cpu = new CPU();
        memory = new Memory();
    }
    // 统一接口
    public void start() {
        cpu.start();
        memory.start();
        System.out.println("电脑启动完成");
    }
}

// 客户端
public class Test {
    public static void main(String[] args) {
        ComputerFacade computer = new ComputerFacade();
        computer.start(); // 无需直接操作子系统
    }
}

10. 组合模式(Composite)的适用场景是什么?

组合模式将对象组合成树形结构,使客户端对单个对象和组合对象(容器)的使用具有一致性。适用于处理层次结构(如文件系统:文件和文件夹,文件夹可包含文件或子文件夹),客户端可统一操作"文件"和"文件夹"。

示例

java 复制代码
import java.util.ArrayList;
import java.util.List;

// 抽象组件
abstract class Component {
    protected String name;
    public Component(String name) { this.name = name; }
    abstract void add(Component c); // 新增子组件(容器实现,叶子不实现)
    abstract void remove(Component c); // 删除子组件
    abstract void display(int depth); // 显示层级
}

// 叶子节点:文件
class File extends Component {
    public File(String name) { super(name); }
    public void add(Component c) { throw new UnsupportedOperationException(); }
    public void remove(Component c) { throw new UnsupportedOperationException(); }
    public void display(int depth) {
        System.out.println("-".repeat(depth) + name);
    }
}

// 容器节点:文件夹
class Folder extends Component {
    private List<Component> children = new ArrayList<>();
    public Folder(String name) { super(name); }
    public void add(Component c) { children.add(c); }
    public void remove(Component c) { children.remove(c); }
    public void display(int depth) {
        System.out.println("-".repeat(depth) + name);
        // 递归显示子组件
        for (Component child : children) {
            child.display(depth + 2);
        }
    }
}

三、行为型设计模式

11. 观察者模式的核心是什么?请实现一个简单的观察者模式。

观察者模式定义对象间的一对多依赖关系,当一个对象(主题)状态改变时,所有依赖它的对象(观察者)会自动收到通知并更新。核心是解耦主题和观察者,主题只需维护观察者列表,无需知道具体观察者类型。例如,天气预报系统中,多个显示器(观察者)订阅天气数据(主题),数据更新时所有显示器同步刷新。

示例

java 复制代码
import java.util.ArrayList;
import java.util.List;

// 主题接口
interface Subject {
    void registerObserver(Observer o); // 注册观察者
    void removeObserver(Observer o);  // 移除观察者
    void notifyObservers();           // 通知所有观察者
}

// 观察者接口
interface Observer {
    void update(float temperature);   // 接收更新
}

// 具体主题:天气数据
class WeatherData implements Subject {
    private List<Observer> observers;
    private float temperature;

    public WeatherData() { observers = new ArrayList<>(); }

    public void registerObserver(Observer o) { observers.add(o); }
    public void removeObserver(Observer o) { observers.remove(o); }
    public void notifyObservers() {
        for (Observer o : observers) {
            o.update(temperature);
        }
    }

    // 数据更新时通知观察者
    public void setTemperature(float temperature) {
        this.temperature = temperature;
        notifyObservers();
    }
}

// 具体观察者:显示器
class Display implements Observer {
    private float temperature;
    public void update(float temperature) {
        this.temperature = temperature;
        display();
    }
    private void display() {
        System.out.println("当前温度:" + temperature + "℃");
    }
}

12. 策略模式与状态模式的区别是什么?

  • 策略模式:定义一系列算法,封装每个算法并使它们可互换,客户端可根据需要选择算法,算法的切换由客户端主动控制。例如,购物车的折扣策略(满减、打折)可通过策略模式动态切换。
  • 状态模式:封装对象的状态及其对应的行为,状态的切换由对象内部条件自动触发,客户端无需知道状态细节。例如,订单的状态(待支付→已支付→已发货)转换由订单内部逻辑控制。
    核心区别:策略模式是"客户端选算法",状态模式是"对象内部状态驱动行为"。

示例

java 复制代码
// 策略接口
interface DiscountStrategy { double calculate(double price); }
// 具体策略:满减
class FullReduction implements DiscountStrategy {
    public double calculate(double price) { return price > 100 ? price - 20 : price; }
}
// 上下文:购物车
class ShoppingCart {
    private DiscountStrategy strategy;
    public void setStrategy(DiscountStrategy strategy) { this.strategy = strategy; }
    public double checkout(double price) { return strategy.calculate(price); }
}
java 复制代码
// 状态接口
interface OrderState { void handle(Order order); }
// 具体状态:待支付
class PendingState implements OrderState {
    public void handle(Order order) {
        System.out.println("订单待支付");
        order.setState(new PaidState()); // 状态转换
    }
}
// 具体状态:已支付(其他状态省略)
class PaidState implements OrderState {
    public void handle(Order order) { System.out.println("订单已支付"); }
}
// 上下文:订单
class Order {
    private OrderState state;
    public Order() { state = new PendingState(); }
    public void setState(OrderState state) { this.state = state; }
    public void process() { state.handle(this); }
}

13. 模板方法模式的核心思想是什么?请举例说明。

模板方法模式在抽象类中定义一个算法的骨架(模板方法),将算法的某些步骤延迟到子类中实现,使子类在不改变算法结构的情况下重定义特定步骤。核心是"抽象父类定义流程,子类实现细节",例如,泡茶和泡咖啡的流程(烧水→加原料→冲泡→倒出)相同,但原料不同,可通过模板方法模式实现。

示例

java 复制代码
// 抽象类:定义模板方法
abstract class Beverage {
    // 模板方法(算法骨架,用final修饰防止子类修改)
    public final void make() {
        boilWater();
        addIngredients(); // 抽象方法,子类实现
        brew(); // 抽象方法,子类实现
        pourInCup();
    }

    private void boilWater() { System.out.println("烧水"); }
    private void pourInCup() { System.out.println("倒入杯子"); }

    protected abstract void addIngredients();
    protected abstract void brew();
}

// 具体子类:咖啡
class Coffee extends Beverage {
    protected void addIngredients() { System.out.println("加咖啡粉"); }
    protected void brew() { System.out.println("冲泡咖啡"); }
}

// 具体子类:茶
class Tea extends Beverage {
    protected void addIngredients() { System.out.println("加茶叶"); }
    protected void brew() { System.out.println("冲泡茶叶"); }
}

14. 迭代器模式的作用是什么?为什么说它支持对集合的多种遍历方式?

迭代器模式提供一种方法顺序访问聚合对象中的元素,而无需暴露其内部结构。通过定义迭代器接口(hasNext()next()),聚合对象可提供多个不同的迭代器实现,支持多种遍历方式(如正序、倒序)。例如,对列表既可按索引正序遍历,也可按元素值倒序遍历,客户端只需使用迭代器接口,无需关心聚合对象的具体结构。

示例

java 复制代码
// 迭代器接口
interface Iterator {
    boolean hasNext();
    Object next();
}

// 聚合接口
interface Aggregate {
    Iterator createIterator();
}

// 具体聚合:列表
class MyList implements Aggregate {
    private String[] items;
    private int size;

    public MyList() { items = new String[10]; }
    public void add(String item) { items[size++] = item; }
    public String get(int index) { return items[index]; }
    public int getSize() { return size; }

    // 创建正序迭代器
    public Iterator createIterator() { return new NormalIterator(this); }

    // 正序迭代器
    private class NormalIterator implements Iterator {
        private MyList list;
        private int index;
        public NormalIterator(MyList list) { this.list = list; index = 0; }
        public boolean hasNext() { return index < list.getSize(); }
        public Object next() { return list.get(index++); }
    }

    // 可新增倒序迭代器(略)
}

15. 命令模式的核心是什么?请实现一个简单的命令模式。

命令模式将请求封装为对象(命令),使客户端可参数化不同的请求、队列请求或记录请求日志,支持撤销操作。核心是"命令对象",它封装了接收者和要执行的动作,客户端通过调用命令对象的execute()方法触发请求,而非直接调用接收者。例如,遥控器(客户端)通过命令对象控制灯光(接收者)的开/关。

示例

java 复制代码
// 命令接口
interface Command {
    void execute();
    void undo(); // 撤销
}

// 接收者:灯光
class Light {
    public void on() { System.out.println("灯开"); }
    public void off() { System.out.println("灯关"); }
}

// 具体命令:开灯
class LightOnCommand implements Command {
    private Light light;
    public LightOnCommand(Light light) { this.light = light; }
    public void execute() { light.on(); }
    public void undo() { light.off(); }
}

// 调用者:遥控器
class RemoteControl {
    private Command command;
    public void setCommand(Command command) { this.command = command; }
    public void pressButton() { command.execute(); }
    public void pressUndoButton() { command.undo(); }
}

16. 责任链模式的适用场景是什么?请举例说明。

责任链模式为请求创建一个接收者对象的链,每个接收者都包含对下一个接收者的引用,请求沿链传递,直到被某个接收者处理。适用于处理具有多个可能处理者的请求,且不确定具体处理者(如审批流程:请假1天→组长审批,3天→经理审批,7天→总监审批)。

示例

java 复制代码
// 抽象处理者
abstract class Approver {
    protected Approver nextApprover; // 下一个处理者
    public Approver(Approver next) { this.nextApprover = next; }
    public abstract void approve(int days);
}

// 具体处理者:组长(处理1天以内)
class GroupLeader extends Approver {
    public GroupLeader(Approver next) { super(next); }
    public void approve(int days) {
        if (days <= 1) {
            System.out.println("组长批准请假" + days + "天");
        } else {
            nextApprover.approve(days); // 传递给下一个处理者
        }
    }
}

// 具体处理者:经理(处理3天以内,其他处理者略)
class Manager extends Approver {
    public Manager(Approver next) { super(next); }
    public void approve(int days) {
        if (days <= 3) {
            System.out.println("经理批准请假" + days + "天");
        } else {
            nextApprover.approve(days);
        }
    }
}

17. 中介者模式的作用是什么?它如何减少对象间的耦合?

中介者模式定义一个中介对象,封装一系列对象的交互,使对象间无需直接通信,而是通过中介者间接交互,从而减少对象间的耦合。例如,聊天室中,用户(同事对象)发送消息无需直接发给其他用户,而是通过聊天室(中介者)转发,用户只需与中介者交互,无需知道其他用户的存在。

示例

java 复制代码
// 中介者接口
interface Mediator {
    void sendMessage(String msg, Colleague colleague);
}

// 同事接口
abstract class Colleague {
    protected Mediator mediator;
    public Colleague(Mediator mediator) { this.mediator = mediator; }
    public abstract void receive(String msg);
    public void send(String msg) { mediator.sendMessage(msg, this); }
}

// 具体同事:用户A
class UserA extends Colleague {
    public UserA(Mediator mediator) { super(mediator); }
    public void receive(String msg) { System.out.println("UserA收到:" + msg); }
}

// 具体同事:用户B
class UserB extends Colleague {
    public UserB(Mediator mediator) { super(mediator); }
    public void receive(String msg) { System.out.println("UserB收到:" + msg); }
}

// 具体中介者:聊天室
class ChatRoom implements Mediator {
    private UserA userA;
    private UserB userB; 

    public void setUserA(UserA userA) { this.userA = userA; }
    public void setUserB(UserB userB) { this.userB = userB; }

    public void sendMessage(String msg, Colleague colleague) {
        if (colleague == userA) {
            userB.receive(msg); // 转发给UserB
        } else {
            userA.receive(msg); // 转发给UserA
        }
    }
}

18. 访问者模式的核心是什么?适用于什么场景?

访问者模式将数据结构与数据操作分离,定义一个访问者接口,包含对每种元素的操作方法,元素类提供accept()方法接收访问者,使新增操作无需修改元素类。适用于数据结构稳定(元素类型固定)但操作多变的场景,例如,电商系统中,商品(元素)的类型固定(食品、电器),但需新增"计算税费""计算折扣"等操作。

示例

java 复制代码
// 访问者接口(定义对所有元素的操作)
interface Visitor {
    void visit(Food food);
    void visit(Electronics electronics);
}

// 具体访问者:计算价格
class PriceVisitor implements Visitor {
    public void visit(Food food) { System.out.println("食品价格:" + food.getPrice()); }
    public void visit(Electronics electronics) { System.out.println("电器价格:" + electronics.getPrice()); }
}

// 元素接口
interface Element {
    void accept(Visitor visitor);
}

// 具体元素:食品
class Food implements Element {
    private double price;
    public Food(double price) { this.price = price; }
    public double getPrice() { return price; }
    public void accept(Visitor visitor) { visitor.visit(this); } // 接收访问者
}

// 具体元素:电器
class Electronics implements Element {
    /* 实现类似Food */
    private double price;
    public Electronics(double price) { this.price = price; }
    public double getPrice() { return price; }
    public void accept(Visitor visitor) { visitor.visit(this); } // 接收访问者
}

19. 备忘录模式的作用是什么?请实现一个简单的备忘录模式。

备忘录模式在不破坏封装的前提下,捕获对象的内部状态并保存,以便后续恢复该状态。适用于需要保存和恢复状态的场景(如游戏存档、编辑器撤销功能)。核心角色:原发器(Originator,创建并保存状态)、备忘录(Memento,存储状态)、负责人(Caretaker,管理备忘录)。

示例

java 复制代码
// 备忘录:存储状态
class Memento {
    private String state;
    public Memento(String state) { this.state = state; }
    public String getState() { return state; }
}

// 原发器:游戏角色
class GameRole {
    private String state; // 状态:位置、血量等

    public void setState(String state) { this.state = state; }
    // 创建备忘录
    public Memento saveState() { return new Memento(state); }
    // 恢复状态
    public void restoreState(Memento memento) { this.state = memento.getState(); }
}

// 负责人:管理备忘录(存档)
class Caretaker {
    private Memento memento;
    public void setMemento(Memento memento) { this.memento = memento; }
    public Memento getMemento() { return memento; }
}

20. 解释器模式的核心思想是什么?适用于什么场景?

解释器模式定义一个语言的语法规则,并构建一个解释器来解释该语言中的句子。核心是将语法规则抽象为表达式类,通过组合表达式来解析复杂语句。适用于简单语法的场景(如数学表达式解析、正则表达式解析),但语法复杂时会导致类爆炸,不推荐使用。

示例(解析简单加法表达式)

java 复制代码
// 抽象表达式
interface Expression {
    int interpret();
}

// 终结符表达式:数字
class NumberExpression implements Expression {
    private int num;
    public NumberExpression(int num) { this.num = num; }
    public int interpret() { return num; }
}

// 非终结符表达式:加法
class AddExpression implements Expression {
    private Expression left;
    private Expression right;
    public AddExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }
    public int interpret() { return left.interpret() + right.interpret(); }
}

// 使用:解析"1+2"
public class Test {
    public static void main(String[] args) {
        Expression expr = new AddExpression(new NumberExpression(1), new NumberExpression(2));
        System.out.println(expr.interpret()); // 输出3
    }
}

写在最后

都看到这了,给个一键三连吧,点赞关注收藏、您的支持是我坚持创作最大的动力~~~

相关推荐
天天摸鱼的java工程师几秒前
如何实现数据实时同步到 ES?八年 Java 开发的实战方案(从业务到代码)
java·后端·面试
掉鱼的猫3 分钟前
老码农教你:Solon + EasyExcel 导出工具
java·excel
only-qi5 分钟前
Spring Boot 实时广播消息
java·spring boot·后端
Java水解5 分钟前
Java开发实习超级详细八股文
java·后端·面试
带刺的坐椅20 分钟前
老码农教你:Solon + EasyExcel 导出工具
java·excel·solon·easyexcel
迷知悟道30 分钟前
java面向对象的四大核心特征之继承---超详细(保姆级)
java
lixn31 分钟前
深入理解JVM字节码:invokedynamic
java·jvm
数据智能老司机34 分钟前
探索Java 全新的线程模型——结构化并发
java·性能优化·架构
数据智能老司机34 分钟前
探索Java 全新的线程模型——作用域值
java·性能优化·架构
数据智能老司机37 分钟前
探索Java 全新的线程模型——并发模式
java·性能优化·架构