重构程序
伟大的创意少之又少,多数时候只是一些小改进。小的改进也是好的。
什么是重构
可以运作的程序跟可以维护的程序之间,还有一道难以言说的鸿沟。
一个程序设计之初,是用来解决特定问题。就像在前面章节的学习中,我们也已经写好
了一个可以运作的 BMI 程序。但是对程序设计来说,当我们写越多程序,我们会希望可以
从这些程序之中,找到一个更广泛适用的法则,让每个程序都清晰易读,从而变得更好修改
与维护。
让程序清晰易读有什么好处呢?当一段程序被写出来,之后我们所要做的事,就是修改
它与维护它。一旦程序越长越复杂,溷乱到无法维护的境界时,就只好砍掉重 练。 所以若
我们能透过某些方式,例如重新组织或部分改写程序码,好让程序容易维护,那麽我们就可
以为自己省下许多时间,以从容迎接新的挑战。
我们回过头来看看前面所写的 Android 程序。Android 平台的开发者已经先依照 MVC
模式,为我们将显示界面所用的 XML 描述档、显示资源所用的 XML 描述档从程序码中区隔
开来。将与程序流程无关的部份分开来组织,让程序流程更清楚,相对易于维护。
而在主要程序码(Bmi.java)方面,虽然程序码量很少,还算好读,但整体上并不那麽令
人满意。例如,假使我们要在这段程序码中再多加上按键、适用于多种萤幕显示模式、或是
再加入选单等等内容,很快地程序码就开始变得复杂,变得不容易阅读,也开始越来越不容
易维护。
因此,在继续新的主题之前,我们先来重构这个 BMI 应用程序。在重构的过程中,也
许我们能学到的东西,比学任何新主题还重要呢 。
MVC
我们打算重构 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
private
private
private
private
Button button_calc;
EditText field_height;
EditText field_weight;
TextView view_result;
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 = new Button.OnClickListener()
{
public void onClick(View v)
{
DecimalFormat nf = new DecimalFormat("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"函式:
代码:
import android.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));
并将"TextView view_result"宣告改放到 findViews 中一次处理好。
现在,整个程序流程是不是清爽了许多呢?
JAVA学习 三(重构程序)
最新推荐文章于 2020-07-09 09:53:52 发布