MVP架构模式:餐厅点餐的有趣故事

故事背景:智能餐厅的点餐系统

想象一下,我们开了一家"代码美味"餐厅,餐厅里有三个角色:

  • 顾客 (View) :只会说"我要点餐"和看最终上来的菜品
  • 服务员 (Presenter) :负责接收订单、协调后厨、把菜品端给顾客
  • 厨师 (Model) :在后厨默默做饭,顾客看不到他

角色分工代码实现

1. 厨师 (Model) - 数据和处理逻辑

java 复制代码
// 厨师 - 负责真正的烹饪工作
public class Chef {
    public interface OnCookingListener {
        void onSuccess(String food);
        void onError(String message);
    }
    
    // 真正的业务逻辑在这里
    public void cookFood(String order, OnCookingListener listener) {
        new Thread(() -> {
            try {
                // 模拟烹饪时间
                Thread.sleep(2000);
                
                switch (order) {
                    case "宫保鸡丁":
                        listener.onSuccess("香喷喷的宫保鸡丁做好了!");
                        break;
                    case "麻婆豆腐":
                        listener.onSuccess("热辣辣的麻婆豆腐出锅了!");
                        break;
                    default:
                        listener.onError("抱歉,这道菜我们不会做");
                }
            } catch (InterruptedException e) {
                listener.onError("厨房出问题了!");
            }
        }).start();
    }
}

2. 服务员 (Presenter) - 业务协调员

java 复制代码
// 服务员 - 连接顾客和厨师的中介
public class Waiter {
    private CustomerView customerView;
    private Chef chef;
    
    public Waiter(CustomerView view) {
        this.customerView = view;
        this.chef = new Chef();
    }
    
    // 接收顾客订单,协调后厨工作
    public void takeOrder(String foodName) {
        // 先告诉顾客:订单已收到
        customerView.showLoading("正在为您准备 " + foodName + "...");
        
        // 然后把订单交给厨师
        chef.cookFood(foodName, new Chef.OnCookingListener() {
            @Override
            public void onSuccess(String result) {
                // 厨师做好了,服务员把菜品端给顾客
                customerView.hideLoading();
                customerView.showFood(result);
            }
            
            @Override
            public void onError(String message) {
                // 厨师说做不了,服务员告诉顾客
                customerView.hideLoading();
                customerView.showError(message);
            }
        });
    }
    
    // 清理工作
    public void onDestroy() {
        customerView = null;
    }
}

3. 顾客 (View) - 界面展示

java 复制代码
// 顾客接口 - 定义顾客能做什么
public interface CustomerView {
    void showLoading(String message);    // 显示等待
    void hideLoading();                  // 隐藏等待
    void showFood(String food);          // 展示菜品
    void showError(String message);      // 展示错误
}

// 具体的顾客 - Activity实现
public class RestaurantActivity extends AppCompatActivity implements CustomerView {
    private TextView statusText;
    private Button orderButton1, orderButton2;
    private ProgressBar progressBar;
    private Waiter waiter;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_restaurant);
        
        // 初始化界面
        statusText = findViewById(R.id.status_text);
        orderButton1 = findViewById(R.id.btn_order1);
        orderButton2 = findViewById(R.id.btn_order2);
        progressBar = findViewById(R.id.progress_bar);
        
        // 请来服务员
        waiter = new Waiter(this);
        
        // 设置点餐按钮
        orderButton1.setOnClickListener(v -> waiter.takeOrder("宫保鸡丁"));
        orderButton2.setOnClickListener(v -> waiter.takeOrder("麻婆豆腐"));
    }
    
    // 实现顾客接口的方法
    @Override
    public void showLoading(String message) {
        runOnUiThread(() -> {
            progressBar.setVisibility(View.VISIBLE);
            statusText.setText(message);
        });
    }
    
    @Override
    public void hideLoading() {
        runOnUiThread(() -> {
            progressBar.setVisibility(View.GONE);
        });
    }
    
    @Override
    public void showFood(String food) {
        runOnUiThread(() -> {
            statusText.setText(food);
            Toast.makeText(this, "用餐愉快!", Toast.LENGTH_SHORT).show();
        });
    }
    
    @Override
    public void showError(String message) {
        runOnUiThread(() -> {
            statusText.setText(message);
            Toast.makeText(this, "出错了!", Toast.LENGTH_SHORT).show();
        });
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 餐厅打烊,服务员下班
        waiter.onDestroy();
    }
}

MVP调用时序图

错误情况的时序图

MVP的核心优势

1. 分工明确,各司其职

  • Model: 只关心数据和业务逻辑(厨师只管做饭)
  • View: 只关心界面显示(顾客只管看和点餐)
  • Presenter: 协调两者(服务员传递信息)

2. 易于测试

java 复制代码
// 可以单独测试Presenter,不需要Android环境
@Test
public void testPresenter() {
    // 创建模拟的View
    CustomerView mockView = mock(CustomerView.class);
    Waiter waiter = new Waiter(mockView);
    
    // 测试点餐逻辑
    waiter.takeOrder("宫保鸡丁");
    
    // 验证View被正确调用
    verify(mockView).showLoading(anyString());
}

3. 代码可维护性高

当需要修改界面时,只需要改动View;

当需要修改业务逻辑时,只需要改动Model;

它们互不影响!

总结

通过这个餐厅的故事,我们可以看到MVP架构就像一家组织良好的餐厅:

  • 顾客 (View) 不需要知道菜品怎么做,只需要表达需求看结果
  • 服务员 (Presenter) 不亲自做饭,但协调整个流程
  • 厨师 (Model) 专心做饭,不直接面对顾客

这种架构让我们的代码更加清晰、可维护、可测试,就像一家运转良好的餐厅一样高效有序!

相关推荐
千里马学框架21 小时前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台21 小时前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone21 小时前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui