JAVA进阶技术之十三:Java与设计模式大揭秘

小标题:揭秘 Java 与设计模式:编程路上的 “指南针” 与 “秘籍”

嘿,各位程序猿/媛们!今天咱就来讲讲 Java 与设计模式那些事儿哈,这可都是咱编程路上的“宝藏秘籍”嘞,学会咯,代码档次“嗖”地一下就上去咯,虽说该掉的头发还是会掉哈,但至少咱写代码的时候能更顺溜不是。

一、啥是设计模式

简单来讲啦,设计模式就好比是建筑图纸啦,是前辈们总结出来应付各种软件开发场景的“超实用”套路哦。它能帮咱们把代码写得又优雅、又好维护、还容易扩展嘞,就跟搭积木似的,照着一定的模式搭,稳稳当当又好看,要是瞎拼凑,说不定一阵风过来就散架咯。

二、23 种设计模式大赏

(一)创建型模式

  1. 单例模式 举例:就拿 Windows 系统的任务管理器来说哈,不管你在系统哪个旮旯调用它,那都是同一个实例啦。在 Java 里呢,就好像咱的数据库连接池啦,全局只要一个实例就行咯,不然资源浪费不说,还容易出乱子哒。

Java 实现代码:

public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

瞅瞅这代码,构造函数私有咯,外面只能通过 getInstance 方法拿到唯一实例,第一次调用的时候创建,之后就一直返回同一个哒。

  1. 工厂模式

举例:你去买手机嘛,总不可能自己动手组装零件咯,找个手机工厂就行啦。在代码里呢,创建对象也可以交给工厂类哒,比如说创建不同形状的图形(圆形、矩形),工厂类根据传进去的参数决定返回哪种图形实例咯。

伪代码示例:

// 图形接口
interface Shape {
    void draw();
}
// 圆形类实现图形接口
class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("画个圆");
    }
}
// 矩形类实现图形接口
class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("画个矩形");
    }
}
// 图形工厂类
class ShapeFactory {
    public Shape getShape(String shapeType) {
        if ("circle".equals(shapeType)) {
            return new Circle();
        } else if ("rectangle".equals(shapeType)) {
            return new Rectangle();
        }
        return null;
    }
}

这工厂就像个万能制造机一样啦,你要啥它就给造啥,代码里对象创建的逻辑都放工厂里,以后要修改创建规则的时候,就不用到处翻代码改咯。

  1. 抽象工厂模式

举例:还是拿手机工厂来讲哈,现在可不单是生产手机咯,还配套生产手机壳、充电器这些配件哒,不同品牌的手机(像苹果、安卓阵营)对应不同风格的配件组合啦。抽象工厂就是把这一系列相关产品的创建封装起来哒。

伪代码(简单示意,复杂点还能分层抽象等):

// 抽象手机产品
interface Phone {
    void call();
}
// 抽象手机壳产品
interface PhoneCase {
    void protectPhone();
}
// 苹果手机实现
class IPhone implements Phone {
    @Override
    public void call() {
        System.out.println("用苹果手机打电话");
    }
}
// 苹果手机壳实现
class IPhoneCase implements PhoneCase {
    @Override
    public void protectPhone() {
        System.out.println("保护苹果手机");
    }
}
// 抽象工厂接口
interface ElectronicFactory {
    Phone createPhone();
    PhoneCase createPhoneCase();
}
// 苹果工厂实现
class AppleFactory implements ElectronicFactory {
    @Override
    public Phone createPhone() {
        return new IPhone();
    }
    @Override
    public PhoneCase createPhoneCase() {
        return new IPhoneCase();
    }
}

这样一套下来,不同品牌生态的创建逻辑就很清晰啦,以后要扩展新品牌的时候,加个对应工厂类就行,不会影响到其他代码哒。

  1. 建造者模式

举例:想象一下你去买电脑哈,有各种配置可选,CPU、内存、硬盘、显卡啥的,你跟店员说你的需求,店员就按照你的要求一点点组装起来。在代码里,比如创建一个复杂的 SQL 查询语句,有查询字段、表名、条件、排序这些部分,建造者模式就可以让你一步一步把这个复杂对象构建出来,而不是一次性在构造函数里写一堆参数。

伪代码:

// 电脑产品类
class Computer {
    private String cpu;
    private String memory;
    private String hardDisk;
    // 省略 get、set 方法
    public static class ComputerBuilder {
        private String cpu;
        private String memory;
        private String hardDisk;
        public ComputerBuilder setCpu(String cpu) {
            this.cpu = cpu;
            return this;
        }
        public ComputerBuilder setMemory(String memory) {
            this.memory = memory;
            return this;
        }
        public ComputerBuilder setHardDisk(String hardDisk) {
            this.hardDisk = hardDisk;
            return this;
        }
        public Computer build() {
            Computer computer = new Computer();
            computer.setCpu(cpu);
            computer.setMemory(memory);
            computer.setHardDisk(hardDisk);
            return computer;
        }
    }
}

使用的时候就像这样:

Computer computer = new Computer.ComputerBuilder().setCpu("Intel i7").setMemory("16G").setHardDisk("512G SSD").build();

是不是很清晰,想改哪个配置就改哪个,代码易读又好维护。

  1. 原型模式

举例:好比你要画好多幅类似的画,一幅画完了,其他的就可以照着这个原型复制,然后再修改一些细节就行咯。在 Java 里,有些对象创建成本高,像加载大数据量的配置文件生成的对象,每次都重新创建太浪费资源,就可以用原型模式,先创建一个原型实例,后面需要的时候克隆一份,再按需修改。

Java 示例(简单示意,需实现 Cloneable 接口):

class Prototype implements Cloneable {
    private String data;
    public Prototype(String data) {
        this.data = data;
    }
    public String getData() {
        return data;
    }
    @Override
    protected Prototype clone() throws CloneNotSupportedException {
        return (Prototype) super.clone();
    }
}

使用时:

try {
    Prototype original = new Prototype("初始数据");
    Prototype clone = original.clone();
    clone.data = "修改后的数据";
    System.out.println(original.getData());
    System.out.println(clone.getData());
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}

(二)结构型模式

  1. 代理模式

举例:你租房找中介嘛,中介就相当于房东的代理啦,你不用直接跟房东扯水电费、房租这些事儿,找中介就行咯。在网络访问里,就好比你访问国外网站,本地代理服务器先帮你去拿数据,再转给你,还能缓存数据,下次访问就快啦。

Java 示例(简单静态代理):

// 抽象主题接口,比如网络访问接口
interface NetworkAccess {
    void access(String url);
}
// 真实主题类,真正执行网络访问的
class RealNetworkAccess implements NetworkAccess {
    @Override
    public void access(String url) {
        System.out.println("正在访问:" + url);
    }
}
// 代理类
class ProxyNetworkAccess implements NetworkAccess {
    private RealNetworkAccess realAccess;
    @Override
    public void access(String url) {
        if (realAccess == null) {
            realAccess = new RealNetworkAccess();
        }
        // 可以加点前置处理,比如权限验证
        System.out.println("权限验证通过,准备访问");
        realAccess.access(url);
        // 后置处理,如缓存数据
        System.out.println("访问完成,缓存数据");
    }
}

代理类控制对真实对象的访问,还能在前后搞点小动作,增强功能哒。

  1. 装饰器模式

举例:你买了杯咖啡哈,想加奶、加糖、加奶油,这些配料就是对咖啡的装饰咯。在代码里,比如说给一个文本框组件,你想给它加个边框、背景色,装饰器模式就能动态扩展功能哒。

伪代码:

// 抽象组件接口,类似可视化组件
interface Component {
    void display();
}
// 基础文本框组件
class TextBox implements Component {
    @Override
    public void display() {
        System.out.println("显示一个文本框");
    }
}
// 装饰器抽象类,实现组件接口,聚合组件
abstract class Decorator implements Component {
    protected Component component;
    public Decorator(Component component) {
        this.component = component;
    }
    @Override
    public void display() {
        component.display();
    }
}
// 具体装饰器,加边框
class BorderDecorator extends Decorator {
    public BorderDecorator(Component component) {
        super(component);
    }
    @Override
    public void display() {
        super.display();
        System.out.println("给组件加上边框");
    }
}
// 加背景色装饰器
class BackgroundDecorator extends Decorator {
    public BackgroundDecorator(Component component) {
        super(component);
    }
    @Override
    public void display() {
        super.display();
        System.out.println("给组件加上背景色");
    }
}

通过层层嵌套装饰器,灵活组合功能,文本框想要啥效果就套啥装饰咯。

  1. 适配器模式

举例:你手机充电器是 Type-C 接口,可手头只有个 USB 线,这时候用个转接头(适配器)就能充上电啦。在代码里,假如老系统有个旧接口方法,新功能要调用,但是参数啥的不匹配,适配器就派上用场,把新参数适配成旧接口能接受的形式哒。

伪代码:

// 旧接口
interface OldInterface {
    void oldMethod(int oldParam);
}
// 旧接口实现类
class OldClass implements OldInterface {
    @Override
    public void oldMethod(int oldParam) {
        System.out.println("旧方法执行,参数:" + oldParam);
    }
}
// 新接口
interface NewInterface {
    void newMethod(String newParam);
}
// 适配器类,实现新接口,适配旧接口
class Adapter implements NewInterface {
    private OldInterface oldObject;
    public Adapter(OldInterface oldObject) {
        this.oldObject = oldObject;
    }
    @Override
    public void newMethod(String newParam) {
        int convertedParam = Integer.parseInt(newParam);
        oldObject.oldMethod(convertedParam);
    }
}

适配器让新旧代码和平共处,协同工作,避免大改老代码哒。

  1. 桥接模式

举例:就好像不同品牌的汽车(宝马、奔驰)和不同类型的发动机(汽油、电动),汽车品牌和发动机类型可以独立变化,通过桥接模式把它们组合起来。在图形绘制里,有不同形状(圆形、矩形)和不同的绘制颜色(红、绿),形状类和颜色类分开,用桥接模式关联,这样增加新形状或新颜色都很方便,不会互相影响。

伪代码:

// 抽象形状接口
interface Shape {
    void draw();
}
// 抽象颜色接口
interface Color {
    void applyColor();
}
// 圆形实现形状接口
class Circle implements Shape {
    private Color color;
    public Circle(Color color) {
        this.color = color;
    }
    @Override
    public void draw() {
        System.out.print("画个圆形,");
        color.applyColor();
    }
}
// 红色实现颜色接口
class Red implements Color {
    @Override
    public void applyColor() {
        System.out.println("颜色是红色");
    }
}

使用:

Circle circle = new Circle(new Red()); 
circle.draw();,

这样形状和颜色解耦,各自扩展容易。

  1. 组合模式

举例:在文件系统里,文件夹可以包含文件和子文件夹,它们在操作上有共性,像显示名称、获取大小等。组合模式就把它们统一成组件,客户端可以用同样的方式处理文件和文件夹,不管是单个文件还是复杂的文件夹结构,代码简洁统一。

伪代码:

// 抽象组件接口
interface Component {
    void display();
}
// 文件类实现组件接口
class File implements Component {
    private String name;
    public File(String name) {
        this.name = name;
    }
    @Override
    public void display() {
        System.out.println("文件:" + name);
    }
}
// 文件夹类实现组件接口,聚合子组件
class Folder implements Component {
    private String name;
    private List<Component> children = new ArrayList<>();
    public Folder(String name) {
        this.name = name;
    }
    public void add(Component component) {
        children.add(component);
    }
    @Override
    public void display() {
        System.out.println("文件夹:" + name);
        for (Component child : children) {
            child.display();
        }
    }
}
  1. 外观模式

举例:你去电影院看电影,不用操心灯光怎么控制、音响怎么调试、屏幕怎么升降,有个操作员(外观类)帮你一键搞定这些复杂操作,你只需要按个播放键就行咯。在代码里,比如一个电商系统有订单处理、库存管理、物流对接等复杂模块,外观模式提供一个简单统一的接口给客户端调用,隐藏内部复杂逻辑。

伪代码:

// 订单处理类
class OrderProcessor {
    public void processOrder() {
        System.out.println("处理订单");
    }
}
// 库存管理类
class InventoryManager {
    public void checkStock() {
        System.out.println("检查库存");
    }
}
// 物流对接类
class LogisticsConnector {
    public void shipGoods() {
        System.out.println("发货");
    }
}
// 外观类
class ECommerceFacade {
    private OrderProcessor orderProcessor;
    private InventoryManager inventoryManager;
    private LogisticsConnector logisticsConnector;
    public ECommerceFacade() {
        orderProcessor = new OrderProcessor();
        inventoryManager = new InventoryManager();
        logisticsConnector = new LogisticsConnector();
    }
    public void buyProduct() {
        orderProcessor.processOrder();
        inventoryManager.checkStock();
        logisticsConnector.shipGoods();
    }
}
  1. 享元模式

定义:享元模式(Flyweight Pattern)运用共享技术有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量,避免大量相似类的开销,从而提高系统资源的利用率。

详细描述:在享元模式中,有一个享元工厂类负责创建和管理享元对象。客户端需要对象时,向工厂请求,工厂首先检查是否已经存在所需对象,如果有则直接返回共享实例,若没有则创建一个新的并存储起来供后续使用。

举例:以游戏开发为例,游戏中有大量的树木、花草等植物对象,它们的外观模型(如纹理、形状)基本相同,只是位置不同。使用享元模式,将植物的外观模型设计为享元对象,由工厂统一管理。当创建新的植物场景时,对于相同外观的植物,只需从工厂获取已有的享元实例,设置不同的位置信息即可,大大节省了内存开销,提升游戏性能。

伪代码示例

// 抽象享元类
abstract class Flyweight {
    abstract void operation(int extrinsicState);
}

// 具体享元类
class ConcreteFlyweight extends Flyweight {
    @Override
    void operation(int extrinsicState) {
        System.out.println("具体享元对象执行操作,外部状态:" + extrinsicState);
    }
}

// 享元工厂类
class FlyweightFactory {
    private final Map<String, Flyweight> flyweights = new HashMap<>();

    Flyweight getFlyweight(String key) {
        if (!flyweights.containsKey(key)) {
            flyweights.put(key, new ConcreteFlyweight());
        }
        return flyweights.get(key);
    }
}

(三)行为型模式

  1. 观察者模式

举例:你在微博关注了某个大 V,大 V 一发新动态,你作为粉丝(观察者)就能收到通知咯。在程序里,比如说电商系统,商品价格变了,关注这个商品的用户(观察者)就得收到消息,好决定买不买哒。

伪代码:

// 抽象观察者接口
interface Observer {
    void update(String message);
}
// 具体观察者,用户类实现
class User implements Observer {
    private String name;
    public User(String name) {
    if (name == null || name.isEmpty()) {
        throw new IllegalArgumentException("用户名不能为空");
    }
    this.name = name;
    }
    @Override
    public void update(String message) {
        System.out.println(name + "收到消息:" + message);
    }
}
// 抽象主题接口,被观察对象接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers(String message);
}
// 具体主题,商品类实现
class Product implements Subject {
    private List<Observer> observers = new ArrayList<>();
    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }
    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }
    @Override
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

主题对象管理观察者,状态一变就通知大伙,松耦合,扩展观察者超容易哒。

  1. 策略模式

举例:出行导航,你可以选开车、公交、步行等不同出行策略,导航软件根据你选的策略规划路线咯。在代码里,比如说电商促销,有满减、折扣、赠品等不同促销策略,订单计算价格时按选定策略算哒。

伪代码:

// 抽象策略接口
interface PromotionStrategy {
    double calculateDiscount(double price);
}
// 满减策略实现
class FullReductionStrategy implements PromotionStrategy {
    @Override
    public double calculateDiscount(double price) {
        if (price >= 200) {
            return price - 50;
        }
        return price;
    }
}
// 折扣策略实现
class DiscountStrategy implements PromotionStrategy {
    @Override
    public double calculateDiscount(double price) {
        return price * 0.8;
    }
}
// 上下文类,用策略
class OrderContext {
    private PromotionStrategy strategy;
    public OrderContext(PromotionStrategy strategy) {
        this.strategy = strategy;
    }
    public double calculateFinalPrice(double price) {
        return strategy.calculateDiscount(price);
    }
}

这样电商系统在搞促销活动的时候,只需要切换不同的策略实现类给到 OrderContext 就行咯,新增促销玩法也不影响其他老代码,维护起来轻松得很嘞。

  1. 模板方法模式

举例:就像冲咖啡哈,步骤基本固定的:烧水、磨豆、冲泡、加奶加糖(可选)。模板方法模式就是把这通用流程定义在抽象父类,可变步骤延迟到子类去实现,像美式咖啡不加奶糖,拿铁就要加。

伪代码:

// 抽象咖啡制作类
abstract class CoffeeMaker {
    public final void makeCoffee() {
        boilWater();
        grindBeans();
        brewCoffee();
        addOptional();
    }
    protected void boilWater() {
        System.out.println("烧水");
    }
    protected void grindBeans() {
        System.out.println("磨豆");
    }
    protected void brewCoffee() {
        System.out.println("冲泡咖啡");
    }
    protected abstract void addOptional();
}
// 美式咖啡类
class Americano extends CoffeeMaker {
    @Override
    protected void addOptional() {
        // 啥也不加
    }
}
// 拿铁咖啡类
class Latte extends CoffeeMaker {
    @Override
    protected void addOptional() {
        System.out.println("加奶加糖");
    }
}

用这个模式,模板定好了大框架,子类按需填空白就行,代码复用率超高,还能满足不同的个性化需求,是不是很妙?

  1. 命令模式

举例:你去餐厅吃饭,点了几个菜,服务员把你点的菜记下来,当成一个个“命令”,交给厨房去执行。在代码里,比如有个图形绘制程序,有画圆、画矩形这些操作,每个操作封装成一个命令类,有个命令调用者负责触发执行,这样一来,如果要新增图形绘制功能,只需要新增对应的命令类,不影响其他部分。 伪代码:

// 抽象命令接口
interface Command {
    void execute();
}
// 画圆命令类
class DrawCircleCommand implements Command {
    @Override
    public void execute() {
        System.out.println("画一个圆");
    }
}
// 画矩形命令类
class DrawRectangleCommand implements Command {
    @Override
    public void execute() {
        System.out.println("画一个矩形");
    }
}
// 命令调用者类
class Invoker {
    private Command command;
    public void setCommand(Command command) {
        this.command = command;
    }
    public void executeCommand() {
        command.execute();
    }
}

使用的时候:

Invoker invoker = new Invoker();
invoker.setCommand(new DrawCircleCommand());
invoker.executeCommand();
  1. 状态模式

举例:咱就说那个交通信号灯哈,红灯、绿灯、黄灯轮流切换,不同灯亮的时候对应不同的通行规则,这就是状态变化。在代码里,比如电商订单有不同状态,待付款、已付款、已发货、已完成,每个状态下用户能做的操作不同,用状态模式把订单状态和对应的操作封装,订单状态切换时,行为跟着变,代码条理清晰得很。

伪代码:

// 抽象状态接口
interface OrderState {
    void handle();
}
// 待付款状态类
class UnpaidState implements OrderState {
    @Override
    public void handle() {
        System.out.println("请尽快付款");
    }
}
// 已付款状态类
class PaidState implements OrderState {
    @Override
    public void handle() {
        System.out.println("订单已付款,等待发货");
    }
}
// 订单类,包含当前状态
class Order {
    private OrderState state;
    public Order(OrderState state) {
        this.state = state;
    }
    public void setState(OrderState state) {
        this.state = state;
    }
    public void handleOrder() {
        state.handle();
    }
}

切换状态示例:

Order order = new Order(new UnpaidState());
order.handleOrder();
order.setState(new PaidState());
order.handleOrder();
  1. 职责链模式

举例:公司请假流程晓得吧,你先跟组长请假,组长批了就完事,要是天数多,组长批不了,就往上找经理,经理再不行就找老板。这就是个职责链,一级一级传递审批请求。在代码里,比如处理网络请求,根据请求类型,先经过权限验证,再日志记录,最后业务处理,每个环节看成一个处理器,组成职责链,请求依次流过,符合条件就处理,不符合就传递给下一个。

伪代码:

// 抽象处理器接口
interface Handler {
    void handleRequest(Request request);
    void setNextHandler(Handler nextHandler);
}
// 权限验证处理器
class AuthHandler implements Handler {
    private Handler nextHandler;
    @Override
    public void handleRequest(Request request) {
        if (request.isValid()) {
            System.out.println("权限验证通过");
            if (nextHandler!= null) {
                nextHandler.handleRequest(request);
            }
        } else {
            System.out.println("权限验证失败");
        }
    }
    @Override
    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }
}
// 日志记录处理器
class LogHandler implements Handler {
    private Handler nextHandler;
    @Override
    public void handleRequest(Request request) {
        System.out.println("记录日志");
        if (nextHandler!= null) {
            nextHandler.handleRequest(request);
        }
    }
    @Override
    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }
}
// 业务处理器
class BusinessHandler implements Handler {
    private Handler nextHandler;
    @Override
    public void handleRequest(Request request) {
        System.out.println("执行业务逻辑");
        if (nextHandler!= null) {
            nextHandler.handleRequest(request);
        }
    }
    @Override
    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }
}

组装并使用职责链:

AuthHandler authHandler = new AuthHandler();
LogHandler logHandler = new LogHandler();
BusinessHandler businessHandler = new BusinessHandler();
authHandler.setNextHandler(logHandler);
logHandler.setNextHandler(businessHandler);
Request request = new Request(true);
authHandler.handleRequest(request);

  1. 中介者模式

举例:像咱们办公室同事之间沟通哈,要是没有个协调人,A 找 B 谈事儿,B 又找 C 确认,乱得很。这时候有个项目经理(中介者),大家都跟他反馈,他再统筹安排,沟通就顺畅多了。在代码里,比如多个游戏角色交互,战士、法师、牧师,他们之间的技能配合、状态同步,如果都互相直接调用,代码耦合严重,引入中介者(游戏控制器),角色只和中介者交互,中介者协调角色间的行为。

伪代码:

// 抽象同事接口
interface Colleague {
    void setMediator(Mediator mediator);
    void sendMessage(String message);
    void receiveMessage(String message);
}
// 战士角色类
class Warrior implements Colleague {
    private Mediator mediator;
    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }
    @Override
    public void sendMessage(String message) {
        mediator.sendMessage(message, this);
    }
    @Override
    public void receiveMessage(String message) {
        System.out.println("战士收到消息:" + message);
    }
}
// 法师角色类
class Mage implements Colleague {
    private Mediator mediator;
    @Override
    public void setMediator(Mediator mediator) {
        this.mediator = mediator;
    }
    @Override
    public void sendMessage(String message) {
        mediator.sendMessage(message, this);
    }
    @Override
    public void receiveMessage(String message) {
        System.out.println("法师收到消息:" + message);
    }
}
// 中介者接口
interface Mediator {
    void sendMessage(String message, Colleague sender);
}

// 游戏控制器类,实现中介者接口
class GameController implements Mediator {
    private Warrior warrior;
    private Mage mage;
    public void registerWarrior(Warrior warrior) {
        this.warrior = warrior;
    }
    public void registerMage(Mage mage) {
        this.mage = mage;
    }
    @Override
    public void sendMessage(String message, Colleague sender) {
        if (sender == warrior) {
            mage.receiveMessage(message);
        } else if (sender == mage) {
            warrior.receiveMessage(message);
        }
    }
}

初始化并使用:

GameController gameController = new GameController();
Warrior warrior = new Warrior();
Mage mage = new Mage();
warrior.setMediator(gameController);
mage.setMediator(gameController);
gameController.registerWarrior(warrior);
gameController.registerMage(mage);
warrior.sendMessage("战士发起冲锋");
  1. 访问者模式

举例:你去逛博物馆哈,有不同的展品,每个展品有自己的介绍,游客(访问者)去参观的时候,展品就把自己的信息展示给游客。在代码里,比如有个电商系统的商品数据结构,有商品、订单、用户等不同类型的对象,要统计数据、生成报表,访问者模式就可以让统计报表类(访问者)去遍历这些对象,获取需要的数据,而不用在每个对象类里写复杂的统计逻辑,解耦效果明显。

伪代码:

// 抽象访问者接口
interface Visitor {
    void visitProduct(Product product);
    void visitOrder(Order order);
    void visitUser(User user);
}
// 统计报表访问者类
class StatisticsVisitor implements Visitor {
    private int productCount;
    private int orderCount;
    private int userCount;
    @Override
    public void visitProduct(Product product) {
        productCount++;
    }
    @Override
    public void visitOrder(Order order) {
        orderCount++;
    }
    @Override
    public void visitUser(User user) {
        userCount++;
    }
    public void showStatistics() {
        System.out.println("商品数量:" + productCount);
        System.out.println("订单数量:" + orderCount);
        System.out.println("用户数量:" + userCount);
    }
}
// 抽象元素接口
interface Element {
    void accept(Visitor visitor);
}
// 商品类,实现元素接口
class Product implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visitProduct(this);
    }
}
// 订单类,实现元素接口
class Order implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visitOrder(this);
    }
}
// 用户类,实现元素接口
class User implements Element {
    @Override
    public void accept(Visitor visitor) {
        visitor.visitUser(this);
    }
}

使用:

StatisticsVisitor visitor = new StatisticsVisitor();
Product product1 = new Product();
Product product2 = new Product();
Order order1 = new Order();
User user1 = new User();
product1.accept(visitor);
product2.accept(visitor);
order1.accept(visitor);
user1.accept(visitor);
visitor.showStatistics();
  1. 备忘录模式

定义:备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便之后恢复对象到原先保存的状态。

详细描述: 它包含三个角色:原发器(Originator)负责创建备忘录并记录当前自身状态;备忘录(Memento)用于存储原发器的内部状态;负责人(Caretaker)负责保存备忘录,但不能对备忘录内容进行操作或访问。

举例说明:在文本编辑器软件中,当用户进行编辑操作时,编辑器可以随时保存当前文档的状态作为备忘录。如果用户误操作,如删除了大量重要内容,就可以从保存的备忘录中恢复之前的文档状态,让用户轻松回到某个历史版本,保证数据的安全性与可回溯性。

伪代码示例

// 备忘录类
class Memento {
    private final String state;

    Memento(String state) {
        this.state = state;
    }

    String getState() {
        return state;
    }
}

// 原发器类
class Originator {
    private String state;

    void setState(String state) {
        this.state = state;
    }

    String getState() {
        return state;
    }

    Memento saveToMemento() {
        return new Memento(state);
    }

    void restoreFromMemento(Memento memento) {
        state = memento.getState();
    }
}

// 负责人类
class Caretaker {
    private final List<Memento> mementos = new ArrayList<>();

    void addMemento(Memento memento) {
        mementos.add(memento);
    }

    Memento getMemento(int index) {
        return mementos.get(index);
    }
}
  1. 解释器模式

定义:解释器模式(Interpreter Pattern)给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

详细描述:它将复杂的语言解析任务分解为一系列简单的解释操作,通过构建抽象语法树,让每个节点代表一个语法元素,由对应的解释器类来处理该节点的语义解释。

举例:在编译器开发中,对于源程序代码,解释器模式就大显身手了。例如,将高级编程语言编写的代码解析为机器能理解的指令。编译器会按照语法规则构建抽象语法树,不同的节点(如变量声明、函数调用、运算表达式等)由对应的解释器处理,最终将整个源程序转化为可执行的二进制代码。

伪代码示例 假设我们有一个简单的数学表达式解释器,支持加法和乘法运算。

// 抽象表达式
interface Expression {
    int interpret();
}

// 终结符表达式 - 数字
class NumberExpression implements Expression {
    private final int number;

    NumberExpression(int number) {
        this.number = number;
    }

    @Override
    public int interpret() {
        return number;
    }
}

// 非终结符表达式 - 加法
class AddExpression implements Expression {
    private final Expression left;
    private final Expression right;

    AddExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret() {
        return left.interpret() + right.interpret();
    }
}

// 非终结符表达式 - 乘法
class MultiplyExpression implements Expression {
    private final Expression left;
    private final Expression right;

    MultiplyExpression(Expression left, Expression right) {
        this.left = left;
        this.right = right;
    }

    @Override
    public int interpret() {
        return left.interpret() * right.interpret();
    }
}
  1. 迭代器模式

定义:迭代器模式(Iterator Pattern)提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示。

详细描述:它将遍历聚合对象的职责分离出来,通过迭代器对象来负责跟踪当前遍历位置、判断是否还有下一个元素等操作,让聚合对象专注于自身业务逻辑,同时为客户端提供统一的遍历接口。

举例说明:在 Java 的集合框架中,如 ArrayList、LinkedList 等都实现了迭代器模式。当我们需要遍历集合中的元素时,无需了解集合内部是如何存储数据的,只需获取对应的迭代器,通过迭代器的 hasNext 和 next 方法就能轻松遍历所有元素。例如,遍历一个存储学生成绩的 ArrayList,代码简洁清晰:

ArrayList<Integer> scores = new ArrayList<>();
scores.add(90);
scores.add(85);
scores.add(95);

Iterator<Integer> iterator = scores.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

伪代码示例

// 抽象迭代器
interface Iterator {
    boolean hasNext();
    Object next();
}

// 具体迭代器
class ConcreteIterator implements Iterator {
    private final List<Object> list;
    private int position = 0;

    ConcreteIterator(List<Object> list) {
        this.list = list;
    }

    @Override
    public boolean hasNext() {
        return position < list.size();
    }

    @Override
    public Object next() {
        if (hasNext()) {
            return list.get(position++);
        }
        return null;
    }
}

// 抽象聚合类
interface Aggregate {
    Iterator createIterator();
}

// 具体聚合类
class ConcreteAggregate implements Aggregate {
    private final List<Object> list = new ArrayList<>();

    void add(Object item) {
        list.add(item);
    }

    @Override
    public Iterator createIterator() {
        return new ConcreteIterator(list);
    }
}

掌握这些设计模式,能让我们在面对复杂的编程需求时,游刃有余地构建高质量的软件系统。它们不仅仅是代码技巧,更是编程思想的升华,助力每一位 Java 开发者迈向更高的编程境界。希望这篇文章能帮助大家加深对这些设计模式的理解,快去实践中运用起来吧!

三、Java 设计模式应用场景

Web 开发:在后端,像处理用户请求,路由分发可以用工厂模式创建不同请求处理器,根据 URL 精准匹配,高效处理;数据库连接管理,单例模式那是标配,保证资源利用最优,避免频繁创建销毁连接把数据库搞崩咯。前端页面构建,装饰器模式给组件加特效、样式,让页面颜值飙升,用户体验拉满。 游戏开发:角色系统,不同角色有不同技能、装备,工厂模式批量生成,快捷又方便;怪物 AI 行为,策略模式切换攻击、逃跑、巡逻套路,让怪物“聪明”起来;游戏关卡加载,模板方法模式定好通用流程,不同关卡个性化定制细节,开发效率蹭蹭涨。 企业级应用:权限管理,代理模式控制用户对敏感资源的访问,安全有保障;报表生成,按不同需求(日报、周报、年报)用策略模式选生成算法,数据精准呈现;系统模块间通信,观察者模式解耦,模块状态更新及时通知关联模块,协同作业不出错。

四、设计模式在不同框架中的应用

Spring 框架

Spring 里的 Bean 默认是单例模式,就像前面说的数据库连接池,整个应用上下文共享一个 Bean 实例,节省创建销毁开销,除非你特殊指定 @Scope("prototype") 改成原型模式,每次获取都新建。

Spring AOP(面向切面编程)底层用到代理模式,对目标对象生成代理,在方法执行前后切入自定义逻辑,比如事务管理,方法执行前开启事务,成功后提交,异常就回滚,代码无侵入,干净利落,业务代码不用操心事务细节,专注业务实现。

MyBatis 框架:在 SQL 语句执行映射这块,用到了建造者模式,把复杂的 SQL 构建过程封装,通过链式调用一步步组装查询条件、结果映射等,像 SelectBuilder.select("*").from("user").where("age > 18"),清晰又方便,比写一长串字符串 SQL 可读性强太多,维护起来也轻松。

JavaFX 框架:界面布局,布局管理器类似装饰器模式,给组件安排位置、大小,还能嵌套组合,像 BorderPane 给组件加边框布局,HBox、VBox 水平垂直排列组件,做出炫酷交互界面,用户操作手感一流。 各位码友,设计模式这玩意儿,学起来是要费点心思,但一旦掌握,代码质量那是质的飞跃,开发效率“爆棚”,以后面对复杂需求,都能淡定自若,轻松化解。赶紧动手把这些模式用到项目里试试,开启你的代码“开挂”之旅吧!要是还有啥不明白的,评论区见,咱一起探讨探讨。

后续我还会分享更多 Java 程序员相关的知识,记得关注怡格网,别错过精彩篇章哦!

最近一直在研究AI公众号爆文的运维逻辑,也在学习各种前沿的AI技术,加入了不会笑青年和纯洁的微笑两位大佬组织起来的知识星球,也开通了自己的星球:

怡格网友圈,地址是:https://wx.zsxq.com/group/51111855584224

这是一个付费的星球,暂时我还没想好里面放什么,现阶段不建议大家付费和进入我自己的星球,即使有不小心付费的,我也会直接退费,无功不受禄。如果你也对AI特别感兴趣,推荐你付费加入他们的星球:

AI俱乐部,地址是:https://t.zsxq.com/mRfPc

建议大家先加

微信号:yeegee2024

或者关注微信公众号:yeegeexb2014

咱们产品成型了之后,咱们再一起进入星球,一起探索更美好的未来!