MVC和MVP

倾然丶 夕夏残阳落幕 提交于 2019-12-14 12:13:20

来自于郭大侠:MVC、MVP、MVVM,谈谈我对Android应用架构的理解

结论:

MVC:Model-View-Controller,经典模式,很容易理解,主要缺点有两个:

  • View对Model的依赖,会导致View也包含了业务逻辑;
  • Controller会变得很厚很复杂。

MVP:Model-View-Presenter,MVC的一个演变模式,将Controller换成了Presenter,主要为了解决上述第一个缺点,将View和Model解耦,不过第二个缺点依然没有解决。

一个获取天气的例子(数据来自阿里的聚合)
MVC
  • Model层
public interface IWeatherModel {
    void getWeather( String cityNumber, OnWeatherListener listener);
}
public class WeatherModelImpl implements IWeatherModel {

    public static final String TAG = "WeatherModelImpl";

    @Override
    public void getWeather(String cityNumber, final OnWeatherListener listener) {
        final Handler mHandler = new Handler();
        OkHttpClient okHttpClient = new OkHttpClient();
        final Request request = new Request.Builder()
                .url("http://apis.juhe.cn/simpleWeather/query?city=" + cityNumber + "&key=天气预报的key值")
                .get()//默认就是GET请求,可以不写
                .build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                Log.d(TAG, "onFailure: ");
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        listener.onError();
                    }
                });
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                // response.body().string()只能调用一次
                String responseStr = response.body() != null ? response.body().string() : "";
                Log.d(TAG, "onResponse: " + responseStr);
                if (response.body() != null) {
                    final Weather weather = JSON.parseObject(responseStr, Weather.class);
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            listener.onSuccess(weather);
                        }
                    });
                }
            }
        });
    }
}
  • Controllor(View)层
public class MainActivity extends AppCompatActivity implements OnWeatherListener {
    private IWeatherModel mWeatherModel;
    private EditText etCity;
    private TextView tvResult;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mWeatherModel = new WeatherModelImpl();
        initView();
    }

    //初始化View
    private void initView() {
        etCity = findView(R.id.et_city);
        tvResult = findView(R.id.tv_result);
    }

    //显示结果
    public void displayResult(Weather weather) {
        tvResult.setText(weather.getReason());
    }

    @SuppressWarnings("unchecked")
    private <T> T findView(int id) {
        return (T) findViewById(id);
    }

    @Override
    public void onSuccess(Weather weather) {
        displayResult(weather);
    }

    @Override
    public void onError() {
        Toast.makeText(this, "获取天气信息失败", Toast.LENGTH_SHORT).show();
    }

    public void go(View view) {
        mWeatherModel.getWeather(etCity.getText().toString().trim(), this);
    }

    public void mvp(View view) {
        startActivity(new Intent(this, MvpActivity.class));
    }
}

例子分析:

  • activity里面的控件必须关心业务和数据,才能知道自己怎么展示。换句话说,我们很难让两个人在不互相沟通的情况下,一人负责获取数据,一人负责展示UI,然后完成这个功能。
  • 所以的逻辑都在activity里面。
MVP

MVP从MVC进化而来,View被拆成了Presenter和View,实现了逻辑处理和View的分离

  • Model层 (跟MVC一样,没有改动)
  • View层
public interface IWeatherView {
    String getCity();

    void setText(Weather weather);

    void showLoading();

    void hideLoading();

    void getError();
}
public class MvpActivity extends AppCompatActivity implements IWeatherView {
    private EditText etCity;
    private TextView tvResult;
    private ProgressBar pbLoading;

    private WeatherPresenter mPresenter = new WeatherPresenter(this);

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_mvp);
        initView();
    }

    //初始化View
    private void initView() {
        etCity = findView(R.id.et_city);
        tvResult = findView(R.id.tv_result);
        pbLoading = findView(R.id.pb_loading);
    }

    @SuppressWarnings("unchecked")
    private <T> T findView(int id) {
        return (T) findViewById(id);
    }

    public void go(View view) {
        mPresenter.getWeather();
    }

    @Override
    public String getCity() {
        return etCity.getText().toString();
    }

    @Override
    public void setText(Weather weather) {
        tvResult.setText(weather.getReason());
    }

    @Override
    public void showLoading() {
        pbLoading.setVisibility(View.VISIBLE);
    }

    @Override
    public void hideLoading() {
        pbLoading.setVisibility(View.GONE);
    }

    @Override
    public void getError() {
        Toast.makeText(this, "获取失败", Toast.LENGTH_LONG).show();
    }
}

  • Presenter层
public class WeatherPresenter {
    private IWeatherModel mModel;
    private IWeatherView mView;

    public WeatherPresenter(IWeatherView mView) {
        this.mModel = new WeatherModelImpl();
        this.mView = mView;
    }

    public void getWeather() {
        mView.showLoading();
        mModel.getWeather(mView.getCity(), new OnWeatherListener() {
            @Override
            public void onSuccess(Weather weather) {
                mView.hideLoading();
                mView.setText(weather);
            }

            @Override
            public void onError() {
                mView.hideLoading();
                mView.getError();
            }
        });
    }
}

例子分析:

  • 定义了 IWeatherView 这个接口(协议),activity里面的控件不需要关心数据,只要实现这个接口在每个方法中“按部就班”的展示UI就行了。
  • MVP成功解决了MVC的第一个缺点,但是逻辑处理还是杂糅在Activity。

下面是例子中的实体类和回调接口:

public class Weather {

    /**
     * reason : 查询成功
     * result : {"city":"苏州","realtime":{"temperature":"4","humidity":"82","info":"阴","wid":"02","direct":"西北风","power":"3级","aqi":"80"},"future":[{"date":"2019-02-22","temperature":"1/7℃","weather":"小雨转多云","wid":{"day":"07","night":"01"},"direct":"北风转西北风"},{"date":"2019-02-23","temperature":"2/11℃","weather":"多云转阴","wid":{"day":"01","night":"02"},"direct":"北风转东北风"},{"date":"2019-02-24","temperature":"6/12℃","weather":"多云","wid":{"day":"01","night":"01"},"direct":"东北风转北风"},{"date":"2019-02-25","temperature":"5/12℃","weather":"小雨转多云","wid":{"day":"07","night":"01"},"direct":"东北风"},{"date":"2019-02-26","temperature":"5/11℃","weather":"多云转小雨","wid":{"day":"01","night":"07"},"direct":"东北风"}]}
     * error_code : 0
     */

    private String reason;
    private ResultBean result;
    private int error_code;

    public String getReason() {
        return reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public ResultBean getResult() {
        return result;
    }

    public void setResult(ResultBean result) {
        this.result = result;
    }

    public int getError_code() {
        return error_code;
    }

    public void setError_code(int error_code) {
        this.error_code = error_code;
    }

    public static class ResultBean {
        /**
         * city : 苏州
         * realtime : {"temperature":"4","humidity":"82","info":"阴","wid":"02","direct":"西北风","power":"3级","aqi":"80"}
         * future : [{"date":"2019-02-22","temperature":"1/7℃","weather":"小雨转多云","wid":{"day":"07","night":"01"},"direct":"北风转西北风"},{"date":"2019-02-23","temperature":"2/11℃","weather":"多云转阴","wid":{"day":"01","night":"02"},"direct":"北风转东北风"},{"date":"2019-02-24","temperature":"6/12℃","weather":"多云","wid":{"day":"01","night":"01"},"direct":"东北风转北风"},{"date":"2019-02-25","temperature":"5/12℃","weather":"小雨转多云","wid":{"day":"07","night":"01"},"direct":"东北风"},{"date":"2019-02-26","temperature":"5/11℃","weather":"多云转小雨","wid":{"day":"01","night":"07"},"direct":"东北风"}]
         */

        private String city;
        private RealtimeBean realtime;
        private List<FutureBean> future;

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public RealtimeBean getRealtime() {
            return realtime;
        }

        public void setRealtime(RealtimeBean realtime) {
            this.realtime = realtime;
        }

        public List<FutureBean> getFuture() {
            return future;
        }

        public void setFuture(List<FutureBean> future) {
            this.future = future;
        }

        public static class RealtimeBean {
            /**
             * temperature : 4
             * humidity : 82
             * info : 阴
             * wid : 02
             * direct : 西北风
             * power : 3级
             * aqi : 80
             */

            private String temperature;
            private String humidity;
            private String info;
            private String wid;
            private String direct;
            private String power;
            private String aqi;

            public String getTemperature() {
                return temperature;
            }

            public void setTemperature(String temperature) {
                this.temperature = temperature;
            }

            public String getHumidity() {
                return humidity;
            }

            public void setHumidity(String humidity) {
                this.humidity = humidity;
            }

            public String getInfo() {
                return info;
            }

            public void setInfo(String info) {
                this.info = info;
            }

            public String getWid() {
                return wid;
            }

            public void setWid(String wid) {
                this.wid = wid;
            }

            public String getDirect() {
                return direct;
            }

            public void setDirect(String direct) {
                this.direct = direct;
            }

            public String getPower() {
                return power;
            }

            public void setPower(String power) {
                this.power = power;
            }

            public String getAqi() {
                return aqi;
            }

            public void setAqi(String aqi) {
                this.aqi = aqi;
            }
        }

        public static class FutureBean {
            /**
             * date : 2019-02-22
             * temperature : 1/7℃
             * weather : 小雨转多云
             * wid : {"day":"07","night":"01"}
             * direct : 北风转西北风
             */

            private String date;
            private String temperature;
            private String weather;
            private WidBean wid;
            private String direct;

            public String getDate() {
                return date;
            }

            public void setDate(String date) {
                this.date = date;
            }

            public String getTemperature() {
                return temperature;
            }

            public void setTemperature(String temperature) {
                this.temperature = temperature;
            }

            public String getWeather() {
                return weather;
            }

            public void setWeather(String weather) {
                this.weather = weather;
            }

            public WidBean getWid() {
                return wid;
            }

            public void setWid(WidBean wid) {
                this.wid = wid;
            }

            public String getDirect() {
                return direct;
            }

            public void setDirect(String direct) {
                this.direct = direct;
            }

            public static class WidBean {
                /**
                 * day : 07
                 * night : 01
                 */

                private String day;
                private String night;

                public String getDay() {
                    return day;
                }

                public void setDay(String day) {
                    this.day = day;
                }

                public String getNight() {
                    return night;
                }

                public void setNight(String night) {
                    this.night = night;
                }
            }
        }
    }
}

public interface OnWeatherListener {
    void onSuccess(Weather weather);

    void onError();
}

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!