You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于设计模式实现运行时对象引用切换:文本型星巴克模拟器屏幕切换问题

用状态模式搞定星巴克模拟器的屏幕切换问题

嘿,你的需求正好契合**状态模式(State Pattern)**的核心思想——把每个屏幕的行为和切换逻辑封装在各自的类里,让Frame只负责管理当前屏幕、分发事件,不用再堆一堆判断逻辑。这样不仅代码更清晰,后续加新屏幕也不用动核心的Frame类,扩展性拉满。

我给你拆解下具体的实现方案:

1. 先给IScreen接口补全关键方法

首先得让IScreen接口具备处理触摸事件并返回下一个屏幕的能力,这样每个屏幕才能自己决定切换逻辑:

public interface IScreen {
    // 处理触摸坐标,返回要切换到的下一个屏幕(返回this表示不切换)
    IScreen handleTouch(int x, int y);
    // 屏幕渲染方法,每个屏幕自己实现渲染逻辑
    void render();
}

2. 让每个屏幕类自己管切换逻辑

比如你的初始屏幕MyCards,把它的触摸区域对应的切换逻辑直接写在类里:

public class MyCards implements IScreen {
    // 可以把按钮区域封装成常量,可读性更高
    private static final Rect MENU_BUTTON = new Rect(80, 180, 120, 220);

    @Override
    public IScreen handleTouch(int x, int y) {
        // 判断是否点击了跳转到Menu的区域
        if (MENU_BUTTON.contains(x, y)) {
            return new Menu();
        }
        // 点击其他区域就留在当前屏幕
        return this;
    }

    @Override
    public void render() {
        System.out.println("=== 我的卡片 ===");
        System.out.println("点击[80-120, 180-220]区域进入菜单");
    }
}

再举个Menu屏幕的例子,它可以处理回到MyCards或者跳转到Payment的逻辑:

public class Menu implements IScreen {
    private static final Rect BACK_BUTTON = new Rect(30, 30, 70, 70);
    private static final Rect PAYMENT_BUTTON = new Rect(130, 130, 170, 170);

    @Override
    public IScreen handleTouch(int x, int y) {
        if (BACK_BUTTON.contains(x, y)) {
            return new MyCards();
        } else if (PAYMENT_BUTTON.contains(x, y)) {
            return new Payment();
        }
        return this;
    }

    @Override
    public void render() {
        System.out.println("=== 菜单 ===");
        System.out.println("点击[30-70, 30-70]返回我的卡片");
        System.out.println("点击[130-170, 130-170]进入支付");
    }
}

3. 简化Frame类的逻辑

现在Frame只需要把触摸事件丢给当前屏幕,然后更新current引用就行,不用自己做任何判断:

public class Frame implements IFrame {
    private IScreen current = new MyCards();

    // 处理触摸事件的方法(你原来的"tou..."应该就是这个)
    public void touch(int x, int y) {
        IScreen nextScreen = current.handleTouch(x, y);
        if (nextScreen != current) { // 只有当屏幕变化时才更新
            current = nextScreen;
            current.render(); // 切换后重新渲染新屏幕
        }
    }

    // 初始化时渲染初始屏幕
    public void init() {
        current.render();
    }

    // 其他无关代码省略
}

为啥这个方案好用?

  • 各司其职:Frame只管屏幕的生命周期,每个屏幕只管自己的渲染和切换,符合单一职责原则。
  • 易扩展:以后加新屏幕(比如OrderHistory),只需要实现IScreen接口,完全不用改Frame的代码。
  • 逻辑清晰:切换逻辑和屏幕绑定,不用在Frame里写一堆if-else判断各种坐标,维护起来超轻松。

可选小优化

  • 如果屏幕不需要每次都新建实例,可以用单例模式复用对象,减少内存开销。
  • 把Rect类封装成通用工具类,方便所有屏幕使用坐标判断。

内容的提问来源于stack exchange,提问作者Paul Roman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:07:16