android代码重构日记(二)——MVC框架

1、什么是mvc框架

MVC是当前比较流行的框架,随便Google下,就可以发现几乎所有的应用程序开发中都采用了MVC框架,例如:.NET,Java Spring,Java Struts,PHP 。那么MVC到底是什么,为什么被广泛使用?

简要说明下,什么是MVC。MVC (Model-View-Controller):M是指逻辑模型,V是指视图模型,C则是控制器。一个逻辑模型可以对于多种视图模型,比如一批统计数据你可以分别用柱状图、饼图来表示。一种视图模型也可以对于多种逻辑模型。使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式,而C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新,这与《设计模式》中的观察者模式是完全一样。具体详细的解析,可以去阅读百度知道中介绍的什么是MVC

采用MVC到底有什么好处?从用户的角度出发,用户可以根据自己的需求,选择自己合适的浏览数据的方式。比如说,对于一篇在线文档,用户可以选择以HTML网页的方式阅读,也可以选择以pdf的方式阅读。从开发者的角度,MVC把应用程序的逻辑层与界面是完全分开的,最大的好处是:界面设计人员可以直接参与到界面开发,程序员就可以把精力放在逻辑层上。而不是像以前那样,设计人员把所有的材料交给开发人员,由开发人员来实现界面。在VS 2008开发工具中设计人员就可以直接通过Silverlight来开发界面,在Eclipes工具中开发Android采用了更加简单的方法,设计人员在DroidDraw中设计界面,以XML方式保存,在Eclipes中直接打开就可以看到设计人员设计的界面。

Android中界面部分也采用了当前比较流行的MVC框架,在Android中M就是应用程序中二进制的数据,V就是用户的界面。Android的界面直接采用XML文件保存的,界面开发变的很方便。在Android中C也是很简单的,一个Activity可以有多个界面,只需要将视图的ID传递到setContentView(),就指定了以哪个视图模型显示数据。

在Android SDK中的数据绑定,也都是采用了与MVC框架类似的方法来显示数据。在控制层上将数据按照视图模型的要求(也就是Android SDK中的Adapter)封装就可以直接在视图模型上显示了,从而实现了数据绑定。比如显示Cursor中所有数据的ListActivity,其视图层就是一个ListView,将数据封装为ListAdapter,并传递给ListView,数据就在ListView中现实。

2、实例

我们打算重构 BMI 程序的部份 java 程序码。既然我们已经照着 Android 平台的作法,套用 MVC 模式在我们的程序组织上,那麽,我们不妨也试着套用同样的 MVC 模式在 Bmi.java 程序码上。

如何套用 MVC 模式到Bmi.java 程序码上呢?

原来的程序片段是这样的

代码:

1  @Override
2  public void onCreate(Bundle icicle) {
3      super.onCreate(icicle);
4      setContentView(R.layout.main);
5           
6      //Listen for button clicks
7      Button button = (Button) findViewById(R.id.submit);
8      button.setOnClickListener(calcBMI);
9  }


上面的程序片段中,包含了所有 Android 程序共用的标准内容,整个程序的大致架构在前面章节中已经讲解过,现在我们从中取出我们感兴趣的部分来讨论:

代码:

Button button = (Button)findViewById(R.id.submit);
button.setOnClickListener(calcBMI);


在第7行我们看到一段程序码来宣告按钮物件,与针对该按钮物件作动作的程序码。button.setOnClickListener 程序码的意义是指定一个函式,来负责处理"按下"这个"按钮"后的动作。

我们可以想像,在同一个画面中,多加入一些按钮与栏位后,"onCreate" 这段程序将变得臃肿,我们来试着先对此稍作修改:

首先,我们可以套用 MVC 模式,将宣告介面元件(按钮、数字栏位)、指定负责函式等动作抽取出来,将 onCreate 函式改写如下

代码:

@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);
    findViews();
    setListensers();
}

接着我们将宣告介面元件的部份写成一个独立的"findViews"函式:

private Button calcbutton;
private EditText fieldheight;
private EditText fieldweight;

private void findViews()
{
    calcbutton = (Button) findViewById(R.id.submit);
    fieldheight = (EditText) findViewById(R.id.height);
    fieldweight = (EditText) findViewById(R.id.weight);
}


顺便将原本很没个性的按钮识别参数"button"改名成"calcbutton",以后在程序中一看到"calcbutton",就知道是一个按下后将开始处理计算工作的按钮。

同样地,我们也将指定特定动作(按按钮)的负责函式独立出来:

代码:

//Listen for button clicks
private void setListensers() {
    calcbutton.setOnClickListener(calcBMI);
}



如此一来,我们就将程序逻辑与介面元件的宣告分离开来,达成我们重构的目的。

完整程序如下:

代码:

package com.demo.android.bmi;

import java.text.DecimalFormat;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class Bmi extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        findViews();
        setListensers();
    }

    private Button button_calc;
    private EditText field_height;
    private EditText field_weight;
    private TextView view_result;
    private TextView view_suggest;

    private void findViews()
    {
        button_calc = (Button) findViewById(R.id.submit);
        field_height = (EditText)findViewById(R.id.height);
        field_weight = (EditText)findViewById(R.id.weight);
        view_result = (TextView) findViewById(R.id.result);
        view_suggest = (TextView)findViewById(R.id.suggest);
    }

    //Listen for button clicks
    private void setListensers() {
        button_calc.setOnClickListener(calcBMI);
    }

    private Button.OnClickListener calcBMI = newButton.OnClickListener()
    {
        public void onClick(View v)
        {
            DecimalFormat nf = newDecimalFormat("0.0");
            double height =Double.parseDouble(field_height.getText().toString())/100;
            double weight =Double.parseDouble(field_weight.getText().toString());
            double BMI = weight / (height *height);
           
            //Present result
           view_result.setText(getText(R.string.bmi_result) + nf.format(BMI));

            //Give health advice
            if(BMI>25){
               view_suggest.setText(R.string.advice_heavy);
            }else if(BMI<20){
               view_suggest.setText(R.string.advice_light);
            }else{
               view_suggest.setText(R.string.advice_average);
            }
        }
    };
}



同样是"calcBMI" 函式,在完整程序中,改将"calcBMI" 函式从原本的"OnClickListener"宣告成 "Button.OnClickListener"。这个改变有什么差别呢?

阅读原本的程序码,在汇入(import)的部分可以看到,"OnClickListener"是来自于"android.view.View.OnClickListener"函式:

代码:

    importandroid.view.View.OnClickListener;



改成"Button.OnClickListener"后,"Button.OnClickListener"就变成来自于"android.widget.Button"中的"OnClickListener"函式,在查阅程序时,整个"Button""OnClickListener"之间的关係变得更清晰。

另外,我们偷偷将"OnClickListener"中其他会存取到的介面元件识别参数,也补进 findViews 宣告中:

代码:

private void findViews()
{
    button_calc = (Button) findViewById(R.id.submit);
    field_height = (EditText) findViewById(R.id.height);
    field_weight = (EditText) findViewById(R.id.weight);
    view_result = (TextView) findViewById(R.id.result);
    view_suggest = (TextView) findViewById(R.id.suggest);
}


同时,我们也把识别参数的命名方法做了统一:按钮的识别参数前加上 "button_"前缀,可输入栏位的识别参数前加上"field_"前缀,用作显示的识别参数前则加上"view_"前缀。将变数名称的命名方法统一有什么好处呢?好处在于以后不管是在命名新变数,或是阅读程序码时,都能以更快速度命名或理解变数的意义,让程序变得更好读。

我们也把原本在程序中直接写进的字串

代码:

TextView result = (TextView)findViewById(R.id.result);
result.setText("Your BMI is "+nf.format(BMI));



改写成

代码:

//Present result
view_result.setText(getText(R.string.bmi_result) + nf.format(BMI));

并将"TextViewview_result"宣告改放到 findViews 中一次处理好。


参考:《Android+MVC框架使用分析》、《深入浅出Android-11-初级-重构程序》


3、我的工作日志

使用strings.xml中的文字,对于API已写好的接口,如gettext(),settext()等,直接将对应定义字符的id号传入即可,对于单独定义字符串,使用getString(R.string.id)获取文字。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值