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

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

相关推荐
叶羽西6 分钟前
Android15 Media框架JNI Interface调试
android
spencer_tseng16 分钟前
anti-screenshot (Android + iOS)
android·ios
程序员Android25 分钟前
Android 相机MFNR 拍照trace 分析
android·数码相机
2501_9159184126 分钟前
基于Mach-O文件的动态库与静态库归属方案及API扫描实践
android·ios·小程序·https·uni-app·iphone·webview
踏雪羽翼26 分钟前
android 实现google 订阅支付
android·支付·订阅·google订阅·谷歌支付
2501_9151063229 分钟前
iOS 证书无法跨电脑使用?签名迁移方法一文讲透
android·ios·小程序·https·uni-app·iphone·webview
Kapaseker33 分钟前
Window 内外藏机巧 旧岗新页见真章
android·kotlin
谪星·阿凯42 分钟前
从XXE遗留疑问到Upload-Labs全通关:文件上传漏洞的溯源与实战突破
android·计算机网络
星轨初途42 分钟前
C++ 类和对象(下):初始化列表、static 成员与编译器优化深度剖析
android·开发语言·c++·经验分享·笔记
恋猫de小郭1 小时前
Flutter 的 build_runner 已经今非昔比,看看 build_runner 2.13 有什么特别?
android·前端·flutter