ect);
}
}
四、数据体、单纯计算
1.数据体
定义:可以转换为字符串而不损失信息的变量或常量是数据体;
依赖硬件的数据都不是数据体;
例如:
C语言指针的值依赖硬件,这个值复制到其他计算机上就没有意义了,因此不是数据体;
Java Bean对象,可以转换为json而不损失信息,因为可以转回去,所以Java Bean对象是数据体;
数字3,可以转为"3"而不损失信息;
byte[]数组对象是数据体;
android.view.View类的对象不是数据体(待补充);
2.单纯计算(Pure Calculation)
定义:以一组数据体作为输入,以一组数据体作为输出的计算称为单纯计算;
[result1 result2 result3] = function([param1 param2 param3])
其中function称为函数体;
3.单纯计算的特征
哲理1:程序执行的过程是通信与计算的过程;程序内部的通信是指内存到其他硬件之间的通信;
单纯计算的特征:
单纯计算只在内存、CPU执行;不涉及和显示屏、文件、网络的通信;
单纯计算过程中,不应该引用全局变量或者给全局变量赋值,引用全局变量是输入,给全局变量赋值是输出;
4.例子
if (validate(input)) {
functionA(input);
}
boolean validate(String input) {
if (input.length() > 5) {
showToast("不能长于5个字符!");
return false;
} else if (!isAlphabet(input)) {
showToast("只能输入字母!");
return false;
} else {
return true;
}
}
其中,showToast()涉及和显示屏通信;
可分离出单纯计算过程validate():
String result = validate(input);
if (result == null) {
functionA(input);
} else {
showToast(result);
}
String validate(String input) {
String result;
if (input.length() > 5) {
result = "不能长于5个字符!";
} else if (!isAlphabet(input)) {
result = "只能输入字母!";
} else {
result = null;
}
}
五、阅读信息量优化
1.模块与阅读信息量
阅读信息量是衡量代码的简单与复杂、阅读的难易程度的一个指标;
A.例子一
public static int function(int a, b, c, d, e, f, g, h) {
a = a + 1;
b = a + b;
c = a + b + c;
d = a + b + c + d;
e = e + 1;
f = e + f;
g = e + f + g;
h = e + f + g + h;
return d + h;
}
划分之后:
public static int function(int a, b, c, d, e, f, g, h) {
d = functionI(a, b, c, d);
h = functionJ(e, f, g, h);
return d + h;
}
private static int functionI(int a, b, c, d) {
a = a + 1;
b = a + b;
c = a + b + c;
d = a + b + c + d;
return d;
}
private static int functionJ(int e, f, g, h) {
e = e + 1;
f = e + f;
g = e + f + g;
h = e + f + g + h;
return h;
}
阅读代码时,需要读懂一个方法内语句之间的关系;
这里只简单的考虑有关或无关这种关系,有关用1表示,无关用0表示;
划分之前,对于function(),由于A语句"a = a + 1"对a的赋值会影响引用了a的B语句"b = a + b"的执行结果,因此认为A语句与B语句有关,记M(A, B) = M(B, A) = 1;
function()的语句之间的关系如下(R表示return语句):
A B C D E F G H R
A 0 1 1 1 0 0 0 0 0
B 1 0 1 1 0 0 0 0 0
C 1 1 0 1 0 0 0 0 0
D 1 1 1 0 0 0 0 0 1
E 0 0 0 0 0 1 1 1 0
F 0 0 0 0 1 0 1 1 0
G 0 0 0 0 1 1 0 1 0
H 0 0 0 0 1 1 1 0 1
R 0 0 0 1 0 0 0 1 0
由于这个矩阵的各个元素出现0或1的概率是1/2,因此这个矩阵的信息量为
I = 9*9*-log2(p) = 9*9*-log2(1/2) = 81 (bit)
即,function()方法的阅读信息量是81(bit);
划分之后,语句之间的关系如下:
function():
I J R
I 0 0 1
J 0 0 1
R 1 1 0
functionI():
A B C D R
A 0 1 1 1 0
B 1 0 1 1 0
C 1 1 0 1 0
D 1 1 1 0 1
R 0 0 0 1 0
functionJ():
E F G H R
E 0 1 1 1 0
F 1 0 1 1 0
G 1 1 0 1 0
H 1 1 1 0 1
R 0 0 0 1 0
这个三个矩阵的信息量为
I = 3*3*-log2(1/2) + 5*5*-log2(1/2) + 5*5*-log2(1/2) = 9 + 25 + 25 = 59 (bit)
即,function()、functionI()、functionJ()这三个方法的阅读信息量一共是59(bit);
由于81 (bit) > 59 (bit),可见,划分之后减少了阅读信息量;
B.例子二:语句的排列顺序产生的信息量
a=0; b=1; c=1;
a=b+c;
a=a+b;
output a; // 3
a=0; b=1; c=1;
a=a+b;
a=b+c;
output a; // 2
从这两段代码可以得知,如果把语句的顺序调换,执行结果就不一样了;
因此程序中语句的排列顺序往往不能改变;
n条语句的排列顺序的信息量等于一个全排列的信息量
p = 1/n!
I = -log2(p) = -log2(1/n!) = log2(n!)
当n = 8时,I = log2(8!) = 15.3(bit)
C.例子三:单条语句的信息量
单条语句的信息量包含引用类和方法产生的信息量;
引用类的信息量 = -log2(1/类的总数) = log2(类的总数);
引用方法的信息量 = log2(某个类的方法的总数);
2.避免变量信息重复
例子如下:
int[] numbers;
int count;
这个两个变量中count是numbers的总和;
由于count可以通过Math.count(numbers)计算得到,因此count包含的信息与numbers包含的信息重复;
这时应该去掉count变量,用int count(int[] numbers) {return Math.count(numbers); }这个函数体来代替;
因此有如下的一般结论:
有几个数据体变量:
DataTypeA dataA;
DataTypeB dataB;
DataTypeC dataC;
如果存在一个函数体functionD,以dataA, dataB作为输入,以dataC作为输出;
DataTypeC functionD(DataTypeA dataA, DataTypeB dataB)
即dataC可由