【编程素质】三层架构、MVC、MVP、MVVM

1,三层架构

1)概念

①DAL - 数据访问层(Data access layer):

对数据库的操作。

②UIL - 界面层(User Interface layer):

显示数据和接收用户输入的数据,为用户提供一种交互式操作的界面。
表示为WEB方式、WINFORM方式。

③BLL - 业务逻辑层(Business Logic Layer):

对数据层的操作,对数据业务逻辑处理。

2)MVC和三层架构

是完全不同的2种设计规范。但核心一致:分层,解耦。
【编程素质】三层架构、MVC、MVP、MVVM_第1张图片

2,MVC (Model View Controller)

【编程素质】三层架构、MVC、MVP、MVVM_第2张图片
各部分之间的通信方式如下:

当用户出发事件的时候,
View传送指令到Controller,
Controller完成业务逻辑后,要求Model改变状态,
Model将新的数据发送到View显示,用户得到反馈

Tips:所有的通信都是单向的。
接受用户指令时,MVC可以分为两种方式。一种是通过View接受指令,传递给Controller;另一种是直接通过Controller接受指令。

1)概念:

①M - 模型(model) :

负责数据存取。

②V - 视图(view):

处理数据显示。

③C - 控制器(controller):

处理业务逻辑。
负责从视图读取数据,控制用户输入,并向模型发送数据。比如:写入数据库记录

2)MVC与设计模式

MVC是复合模式,结合了:观察者模式、策略模式、组合模式。

①复合模式:

结合两个或两个以上的模式,组成一个解决方案,解决一再发生的一般性问题。

②从设计模式的角度看待M、V、C关系

【编程素质】三层架构、MVC、MVP、MVVM_第3张图片

③观察者模式:

模型是被观察者。
同一个模型可同时使用多个视图,当状态改变时,相关对象将持续更新。

④策略模式:

控制器是视图的策略。
视图只关心系统中可视的部分,对于任何界面行为,都委托给控制器处理。
控制器负责和模型交互来传递用户请求,对于工作是怎么完成的,视图毫不知情。

⑤组合模式:

视图使用组合模式实现用户界面。
用户界面通常组合了嵌套的组件,像面板、框架和按钮。

3)优缺点

缺点:view层和model层相互可知,可能存在耦合。(演化出了MVP、MVVM这两种框架)

4)android框架MVC

对于原生的android项目:

①model层

java bean,类似repository类(spring中的注解:@Repository用于标注数据访问组件,即DAO组件)

注意:
对数据库的操作、网络等操作都应该放在model里面处理,当然对业务计算等操作也应该放在该层。

②view层

layout.xml、JS+html

③controller层

各类activity。

**注意:
不要在activity中写代码,要通过activity交割model业务逻辑处理,这样避免了activity执行耗时操作。**

3,MVP框架

【编程素质】三层架构、MVC、MVP、MVVM_第4张图片
为了解决MVC耦合过重的问题,MVP的核心思想就是提供一个Presenter将视图逻辑I和业务逻辑相分离,达到解耦的目的。

1)Model | bean

提供数据。

2)View

activity和fragment。用于显示数据。

3)Presenter

负责逻辑的处理,处理关于用户事件的转发。
view层和presenter层的通信是通过接口实现的:activity、fragment可以去实现定义好的接口,而在对应的presenter中通过接口调用方法。

如果要实现的UI比较复杂,而且相关的显示逻辑还跟Model有关系,就可以在View和Presenter之间放置一个Adapter。由这个 Adapter来访问Model和View,避免两者之间的关联。而同时,因为Adapter实现了View的接口,从而可以保证与Presenter之间接口的不变。这样就可以保证View和Presenter之间接口的简洁,又不失去UI的灵活性。

4)与MVC区别

view层和model层不再相互可知,解耦。Presenter完全把Model和View进行了分离。通过MVP模式,可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试。这就解决了MVC模式中测试,维护难的问题。

在MVP模式里,View只应该有简单的Set/Get的方法,用户输入和设置界面显示的内容,除此就不应该有更多的内容,绝不容许直接访问Model–这就是与MVC很大的不同之处。

Android中最早的方案。Activity/Fragment这些上帝角色既承担了V的角色,也承担了C的角色,小项目开发起来十分顺手,大项目就会遇到耦合过重,Activity/Fragment类过大等问题。

5)Android中MVP写法

【编程素质】三层架构、MVC、MVP、MVVM_第5张图片

BasalView

所有View的基类。以接口形式实现。
i>其中方法:
getContext方法必须有。
余下方法可根据需要自行创建。笔者这创建的其余3个方法是对话框方法。是为了在CouponPresenter中可以直接调用对话框:basalView.showCircleProgressDialog();
ii>关联性
BasalAcivity、BasalFragment实现该接口和其中所有方法,避免在每个Acitivity中实现这些方法。
iii>代码

public interface BasalView {
    Context getContext();
    void showCircleProgressDialog();
    void showToastShort(String message);
    void dismissCircleProgressDialog();
    void clearCircleProgressDialog();
}

BasalContract

契约类。所有Contract基类。
contract包定义了一系列的接口,用于联系View层和Presenter层。
i>方法:
两个方法,顾名思义,用来绑定和解除View。
ii>关联性:
所有contract接口实现该接口。
iii>代码:

public interface BasalContract<T extends BasalView> {
    void attachView(T basalView);
    void detachView();
}

BasalActivity

Acitivity基类。
i>关联性:
a.实现BasalView接口及其中方法
b.泛型类,绑定Presenter。
重点在于在initialize方法种绑定了Presenter,在onDestroy方法中解绑了Presenter。其余方法可根据需求自定义添删。
在具体的Acitivity中,通过initPresenter方法返回具体的Presenter.
c.抽象类。所有Activity继承此类。
ii>代码:

public abstract class BasalActivity<T extends BasalContract> extends AppCompatActivity implements BasalView {
    public T presenter;
    /**
     * 获取布局资源
     *
     * @return
     */
    protected abstract int getLayoutId();

    /**
     * 初始化布局控件
     */
    protected abstract void initView();

    /**
     * 初始化Presenter
     *
     * @return
     */
    protected abstract T initPresenter();

    /**
     * 加载数据
     */
    protected abstract void loadData();

    /**
     * 为控件绑定事件
     */
    protected abstract void viewOption();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // removeStatusBar();
        super.onCreate(savedInstanceState);
        setContentView(getLayoutId());
        initialize();
    }

    private void initialize() {
        presenter = initPresenter();
        if (presenter != null) {
            presenter.attachView(this);
        }
        initView();
        loadData();
        viewOption();
    }

    @Override
    public Context getContext() {
        return getActivity();
    }

    protected Activity getActivity() {
        return this;
    }

    @Override
    protected void onDestroy() {
        if (presenter != null) {
            presenter.detachView();
        }
        clearCircleProgressDialog();
        super.onDestroy();
    }

    //转圈
    private CircleProgressDialog circleProgressDialog;

    @Override
    public void showToastShort(String message) {

        Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void showCircleProgressDialog(){
        if (null == circleProgressDialog){

            circleProgressDialog = new CircleProgressDialog(this);
            circleProgressDialog.setCancelable(false);
        }else{

            dismissCircleProgressDialog();
        }
        circleProgressDialog.showDialog();
    }
    @Override
    public void dismissCircleProgressDialog(){

        if (null != circleProgressDialog) {
            circleProgressDialog.dismiss();
        }
    }
    @Override
    public void clearCircleProgressDialog(){

        if (null != circleProgressDialog) {
            circleProgressDialog.dismiss();
        }
        circleProgressDialog = null;
    }
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    protected void removeStatusBar() {
        // 当系统版本为4.4或者4.4以上时可以使用沉浸式状态栏
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
        }
    }
}

BasalFragment

Fragment基类。类似BasalActivity。
在此处仅贴出重要部分代码。

public abstract class BasalFragment<T extends BasalContract> extends Fragment implements BasalView {
    protected T presenter;
    Context context = null;
    private View rootView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        rootView = inflater.inflate(getLayoutId(), container, false);
        ButterKnife.bind(this, rootView);
        context = getActivity();
        initialize();
        return rootView;
    }

    protected void initialize() {
        presenter = initPresenter();
        if (presenter != null) {
            presenter.attachView(this);
        }
        initView();
        loadData();
        viewOption();
    }

    @Override
    public void onDestroyView() {
        if (presenter != null) {
            presenter.detachView();
        }
        super.onDestroyView();
    }

    /**
     * 初始化presenter
     *
     * @return
     */
    protected abstract T initPresenter();

    /**
     * 初始化视图控件
     */
    protected abstract void initView();

    /**
     * 加载数据
     */
    protected abstract void loadData();

    /**
     * 绑定事件
     */
    protected abstract void viewOption();

    /**
     * 获取布局资源文件
     *
     * @return
     */
    protected abstract int getLayoutId();

    @Override
    public Context getContext() {
        return getActivity();
    }

BasalPresenter

Presenter基类。

public abstract class BasalPresenter<T extends BasalView> implements BasalContract<T>{
    protected Context context;
    protected  T baselView;

    @Override
    public void attachView(T basalView) {
        this.baselView = basalView;
        context = baselView.getContext();
    }

    @Override
    public void detachView() {
        baselView = null;
    }
}

CouponContract

该处举例一个优惠券功能的获取,并填充界面的功能。
i>关联性
由于在BasalPresenter中已经实现了BasalContract,对View已经绑定,在此不再实现。
在这个方法中定义其对应的Presenter中具体应该做什么方法。
ii>代码

public interface CouponContract {
    void getCouponData(final int page, String typeStr);
}

CouponPresenter

这个类
i>关联性
实现对应的Contract接口。继承BasalPresenter,并传入对应的View(如CouponView)。
获取到数据后,进行处理,然后通过basalView.方法,传给对应界面(如实现了CouperView的CouponFragment)
ii>代码

public class CouponPresenter extends BasalPresenter<CouponView> implements CouponContract {
    @Override
    public void getCoupon(GetCouponRequest getCouponRequest,final int page, String typeStr) {

        basalView.showCircleProgressDialog();

        getCouponRequest.request(context, page + "", typeStr).setOnRequestListener(new OnRequestListener() {
            @Override
            public void resultBack(RequestDataBean requestDataBean) {

                basalView.dismissCircleProgressDialog();
                basalView.getCouponListSuccess(page,requestDataBean);
            }
            @Override
            public void onError(Throwable e) {

                basalView.dismissCircleProgressDialog();
                basalView.getCouponListFall();
            }
        });
    }
}

CouponView

i>方法:
对应Fragment或Acitivity中,需要填充数据的地方。
ii>代码

public interface CouponView extends BasalView {
    void getCouponListSuccess(int page, RequestDataBean requestDataBean);
    void getCouponListFall();
}

CouponFragment

具体显示界面的类。
i>方法
initPresenter()方法中返回具体的Presenter。
ii>关联性
继承BasalFragment,并指定泛型CouponPresenter。
实现CouponView,并实现其中方法。在这些方法中我们会获取对应的数据,只需要进行数据的填充即可。需要进行的逻辑处理可在对应的Presenter中进行。
iii>代码
仅显示关键部分代码:

public class CouponFragment extends BasalFragment<CouponPresenter> implements CouponView {
    @Override
    protected void loadData() {
        presenter.getCoupon(getCouponRequest, pageList, couponType);
    }
    @Override
    protected void viewOption() {

    }
    @Override
    protected int getLayoutId() {
        return R.layout.fragment_coupon;
    }
    @Override
    protected CouponPresenter initPresenter() {
        return new CouponPresenter();
    }
    @Override
    protected void initView() {
        setCouponRecyclerView();
    }
    @Override
    public void getCouponListSuccess(int page, RequestDataBean requestDataBean) {

        resultSuccess(page, requestDataBean);
    }
    @Override
    public void getCouponListFall() {
    }
}

4,MVVM

最早由微软提出的。
【编程素质】三层架构、MVC、MVP、MVVM_第6张图片
MVVM模式将Presenter改名为ViewModel,基本上与MVP模式完全一致。

唯一的区别是,它采用双向绑定(data-binding):View的变动,自动反映在ViewModel,反之亦然。
这套框架最早使用的data-binding将数据绑定到xml里,这么做在大规模应用的时候是不行的,不过数据绑定是一个很有用的概念,后续Google又推出了ViewModel组件与LiveData组件。
ViewModel组件规范了ViewModel所处的地位、生命周期、生产方式以及一个Activity下多个Fragment共享ViewModel数据的问题。LiveData组件则提供了在Java层面View订阅ViewModel数据源的实现方案。

你可能感兴趣的:(编程素质)