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

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

相关推荐
用户2018792831674 小时前
MVVM 架构模式:咖啡馆的智能点餐系统
android
用户2018792831674 小时前
浅析Android MVC架构
android
AsiaLYF5 小时前
kotlin中MutableStateFlow和MutableSharedFlow的区别是什么?
android·开发语言·kotlin
2501_916008896 小时前
iOS 发布全流程详解,从开发到上架的流程与跨平台使用 开心上架 发布实战
android·macos·ios·小程序·uni-app·cocoa·iphone
4Forsee6 小时前
【Android】浅析 Android 的 IPC 跨进程通信机制
android·java
叶羽西6 小时前
如何区分Android、Android Automotive、Android Auto
android
用户2018792831676 小时前
用 “奶茶店订单系统” 讲懂 MVI 架构
android
LiuYaoheng7 小时前
【Android】布局优化:include、merge、ViewStub的使用及注意事项
android·java
Kapaseker7 小时前
Kotlin Flow 的 emit 和 tryEmit 有什么区别
android·kotlin