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) 专心做饭,不直接面对顾客

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

相关推荐
fundroid1 小时前
Android Studio + Gemini:重塑安卓 AI 开发新范式
android·android studio·ai编程
vortex52 小时前
谷歌黑客语法挖掘 SQL 注入漏洞
android·数据库·sql
-指短琴长-5 小时前
MySQL快速入门——基本查询(下)
android·mysql·adb
stevenzqzq6 小时前
android lambda回调
android
林北北的霸霸9 小时前
django初识与安装
android·mysql·adb
Java 码农10 小时前
MySQL EXPLAIN 详解与优化指南
android·mysql·adb
stevenzqzq14 小时前
Android Hilt 入门教程_传统写法和Hilt写法的比较
android
wuwu_q15 小时前
用通俗易懂方式,详细讲讲 Kotlin Flow 中的 map 操作符
android·开发语言·kotlin
_李小白15 小时前
【Android FrameWork】第五天:init加载RC文件
android
2501_9160074715 小时前
手机使用过的痕迹能查到吗?完整查询指南与步骤
android·ios·智能手机·小程序·uni-app·iphone·webview