【大龙驹.共享贴】编程过程中需要注意的一些问题【初级】

beyondtkl 2005-01-10 04:23:02
老大叫写一些需要注意的地方,要求不要太高级,下午写了点,顺便拿来共享 ^_^。。

也顺便希望大家补充,建议,谢谢。<还在继续写>

-------------------------------------------
设计、编程规范
本规范粗略确定一些具体编程中的规范,我们编程首先看重的是能够运行起来,而且是安全的运行,然后是可读性、可维护性、可移植性,其次是高效率性,最后是可扩充性。我们在具体编程过程中,应该尽量考虑是否安全的运行,是否能很容易的让人理解,是否为高效的代码,绝不能只是简单的实现了当前的功能而已。

本规范列出了具体开发过程中可能出现的错误,请大家补充。

一. 安全性的编程
0. 我们自己书写的函数、过程,应当尽可能的被客户端安全的调用,即使客户端是错 误的调用,所以就要求对函数(过程)的参数进行足够的判断。
1. 防止数组越界,注意数组的下标以及上限,使用Low,High确定其下标及上限。
2. 使用指针,对象时最好先判断其是否为空,使用完后,请记得在必要的时候释放其所指向的空间,并重赋值为nil,使用方法为GetMem/FreeMem, New/Dispose配对。
3. 防止使用可能被优化的数据
比如 for I := 0 to 100 do
begin // 循环代码 end;
J := I; // 注意:此处的I的值不一定就是101,因为I可能被优化,所以这种风格 是不安全的,而万一出现问题,则是非常隐蔽的BUG,安全的形式是以另外一个变量 同时进行增加。
4. 定义变量,函数返回值请尽量先初始化,防止变量使用前没进行有意义的初始化,包括自定义的变量以及函数的返回值。
5. 字符串注意空格,保口是否保留空格,是否截空等处理,尤其是在字符串的比较的时候需要注意空格。
6. 字符NULL,包括不同数据库的具体意义,实现以及Delphi前台的意义,需要注意。
7. 浮点数的比较不一定可靠,因为浮点数的实现跟机器相关,不同的机器可能具有不同的精度。
8. 所有的循环操作注意结束条件,以及对控制变量的处理,比如在数据集的循环处理时,请记得写AdoQry.Next,以避免死循环。
9. 当类型转换时,需要考虑如果转换不成功时的处理,比如StrToInt(a); 如果转换不成功的话,那么就会出现错误,所以这种情况,请尽量用StrToIntDef,StrToFloatDef等函数进行转换。
10. 注意数据的溢出可能,比如数据库中的主键为12位整型,能表达的数范围为10^12-1,如果我们用 StrToInt的话,那么可能就会出现数据的截断,因为10^12大于Integer所能表示的范围2147483647, 那么就可能发生截断从而主键重复的错误(虽然这种可能性比较少,但是请尽量避免错误),所以考虑可以使用StrToInt64,否则会出现这种非常难以发现的BUG。
11. 进行事务处理时,请不要在自己的事务处理中直接提交当前别的事务,否则这是非常难以发现的BUG,而且可能导致严重的错误,因为这种行为是在背后进行的,且无法预料,所以坚决避免。
12. 使用动态数组之前请记得先SetLength,使用类似TList,TStringList之类的动态容器时,使用前,请用 .Create先构造分配空间,最后如果容器里面保存的是指针,还需要循环释放里面的指针所指向的空间,最后再.Free本容器,以免造成内存泄漏,注意我们一般使用的是Count属性,非Capacity属性。
13. 使用动态库之类的,请尽量用动态调用,避免出现如果客户端没有DLL就不能启动应用程序的情况,增强健壮性。
14. 可能出错的代码请尽量用try except end异常处理保护起来, 并考虑尽可能的记载下来,进行恢复,尤其当与数据库交互时,所有访问点请尽量用try, except, end保护起来,并对不同的错误代码进行不同的处理,比如与数据库的连接中断等,如果遇到这种情况,就一定要处理好。
15.


二. 可读性、可维护性、可移植性
1. 模块,单元应该有对整体的说明信息,重要函数、过程、变量尽量有有意义的注释信息,且注意区分大小写。
2. 事件响应代码,业务处理代码请尽量以函数,过程进行封装,且函数过程的代码不要过长,即:函数,过程的功能应该尽可能简单,以具有比较好的可维护性以及重用性。
3. 尽可能的声明为函数,且返回有意义的值。当然,如果函数体不可能出现某种异常的话,那么可以声明为过程即可。
4. Form,Unit,函数,过程间尽量以函数(过程)参数的形式进行传递,不能以Form的公有变量(数据)进行直接绑定,这样会增加模块间的耦合度,使得具有更差的可移植性,可维护性。
5. 变量,过程名,函数名,结构体等的命名尽量有意义,且符合规范。
6. 功能相似的代码请尽量抽象为过程、函数,提高代码的重用度以及维护性。
7. 数据,数据结构定义,业务逻辑处理请尽量抽象分开保存到另外单独的.pas单元中,即前台控制与业务处理尽量分开。
8. 可以考虑使用更有意义的状态代替某些初始状态,比如数据库中0代表男性,1代表女性,那么我们可能这样的方式进行代替:
type SexFlag = ( sMale = 0, sFemale = 1 ); 从而这样更具有意义,增强可读性,并 增强了独立性。
9. 尽量提供有意义、合适的提示信息。
10.


三. 高效率的编程
1. 尽可能的对信息进行封装,,尽可能少的定义public数据成员,尽可能避免直接使用其他Form的public成员进行访问,而应当考虑使用统一的接口进行访问,比如:

TForm1:
Pulic:CreateFlag: string;
调用:
Form1 := Tform1.Create(Self);
Form1.CreateFlag := ‘add’;
Form1.Left := 100;
// 以上使用方法虽然比较常见,缺是非常不好的设计方法,不符合OO思想,应该采取下面的方法:
TForm1:
private:
CreateFlag: string;
public:
constructor Create(AOwner: TComponent; crFlag:string; nLeft:Integer);
begin
inherited(AOwner);
CreateFlag := ‘add’;
Left := nLeft; // ….
end;
调用:
Form1 := TForm1.Create(Self, ‘add’, 100);
这样达到了信息封装的目的,而且使用统一的接口进行存取,使得耦合度降低, 更容易维护等。
2. 定义结构体时,请尽量用静态维数的数组,尽量少用string,因为string类型为动态增长的数据类型,会导致运行时时间成本增加。比如:
数据表: Person
P_ID: char[10]
P_Name: char[10];
我们定义相应的结构体时,应该这样定义: (1)
type PersonRec = record
pID: array[0..10] of char;
pName: array[0..10] of char;
end;
// 因为我们明确的知道字段的长度,那么就定义相应的静态数组,这就是所谓的以空间换时间的设计方法。
而如果这样定义时: (2)
type PersonRec = record
pID: string;
pName: string;
end;
// 虽然 这样也可以 但是存在一些缺陷:
A. 导致运行时时间成本的增加,由string的动态增长性质确定
B. 在使用指针类型转换时,采取这种形式可能会出错或者转换不正确。
3. 多个if else if ..else分支时,请尽量用case of进行代替,后者的效率更高。
4. 当需要对某个函数的返回值做多次分支判断、多次存取时,应该用局部变量储存其返回值,比如应该:
I := FuncA;
if I > 10 then
else if I > 5 then
else ….
而不是
if FuncA >10 then
else if FuncA > 5 then

这样会多次存取,使得效率低下,甚至可能出现错误。
5.

四. 可扩充性
1. 分支执行语句请尽量以 begin end括起来,比如
if a > 0 then
begin

end
else
begin

end;
哪怕只有一句执行代码,因为可能在将来的版本中会增加处理代码,这样会方便将来。
2. 分支执行语句请考虑条件状态的扩充 比如数据库某个字段的现有状态为’0’,’1’
为了考虑扩充性,下面的写法不妥:
if FieldByName(‘aaa’).AsString = ‘0’ then
//…
else
//…
因为可能将来会增加一个新状态’2’,那么到时候就很难知道但前的else指的是哪种状态,而这么写则比较合适:
if .. = ‘0’ then
//
else if .. = ‘1’ then
// ..

3.
五. 一些基本的API函数
1. ZeroMemory, FillChar
比如 rec为一个record类型的变量(非指针类型),初始化可以用
ZeroMemory(@rec, SizeOf(rec)) 或 FillChar(rec, SizeOf(rec), 0); 而不需要用单独为 其每个成员初始化的形式,比如 rec.a := 0;rec.b := ‘’;这样是效率低下的,如果还想有特殊的初始化 可以这样 ZeroMemory, FillChar之后 rec.a := 1;
2. StrCopy,
六.
...全文
361 39 打赏 收藏 转发到动态 举报
写回复
用AI写文章
39 条回复
切换为时间正序
请发表友善的回复…
发表回复
g961681 2005-01-12
  • 打赏
  • 举报
回复
收藏
zglwxb 2005-01-12
  • 打赏
  • 举报
回复
收藏

cdsgajxlp 2005-01-12
  • 打赏
  • 举报
回复
up
songyanbin 2005-01-12
  • 打赏
  • 举报
回复
强贴 关注 收藏 学习中。。。
hellolongbin 2005-01-12
  • 打赏
  • 举报
回复
先顶后看
drift1981 2005-01-12
  • 打赏
  • 举报
回复
up,学习c++
beyondtkl 2005-01-12
  • 打赏
  • 举报
回复
好 感謝樓上!!

就是要這樣~~~~~~~~~~~~~共享 交流
僵哥 2005-01-12
  • 打赏
  • 举报
回复
相对数据库而言增加一点点:

1.一对多关系当中做子表新增或修改时,应锁定母表相关记录。
2.修改甚至必要时在确认删除前要对相关记录做锁定。
3.对表内容做批次未可对需要异动数据做精确定位的做表锁。
4.启用事务。
5.事务处理过程当中,若部分数据需要其它子程序做调整,而当前事务无法控管到部分,做好预先及善后处理工作。

特别是在做分布式作业系统当中,以上问题被不少人所忽略,而导致两位用户同时修改同一条记录,而先完成修改的用户总是得不到正克的结果,或者干脆A用户在修改M表03记录所对应的子表数据,B用户却删除掉了M表03记录……
yueyixing 2005-01-12
  • 打赏
  • 举报
回复
gz,继续啊!
beyondtkl 2005-01-12
  • 打赏
  • 举报
回复
我看結貼算了。。
jackie168 2005-01-12
  • 打赏
  • 举报
回复
顶一下。。。
beyondtkl 2005-01-12
  • 打赏
  • 举报
回复
三. 高效率的编程
1. 尽可能的对信息进行封装,尽可能少的定义public数据成员,尽可能避免直接使用其他Form的public成员进行访问,而应当考虑使用统一的接口进行访问,比如:

TForm1:
Pulic:CreateFlag: string;
调用:
Form1 := Tform1.Create(Self);
Form1.CreateFlag := ‘add’;
Form1.Left := 100;
// 以上使用方法虽然比较常见,却是非常不好的设计方法,不符合OO思想,应该采取下面的方法:
TForm1:
private:
CreateFlag: string;
public:
constructor Create(AOwner: TComponent; crFlag:string; nLeft:Integer);
begin
inherited Create(AOwner);
CreateFlag := ‘add’;
Left := nLeft; // ….
end;
调用:
Form1 := TForm1.Create(Self, ‘add’, 100);
这样达到了信息封装的目的,而且使用统一的接口进行存取,使得耦合度降低, 更容易维护等。
2. 定义结构体时,请尽量用静态维数的数组,尽量少用string,因为string类型为动态增长的数据类型,会导致运行时时间成本增加。比如:
数据表: Person
P_ID: char[10];
P_Name: char[10];
我们定义相应的结构体时,应该这样定义: (1)
type PersonRec = record
pID: array[0..10] of char;
pName: array[0..10] of char;
end;
// 因为我们明确的知道字段的长度,那么就定义相应的静态数组,这就是所谓的以空间换时间的设计方法。
而如果这样定义时: (2)
type PersonRec = record
pID: string;
pName: string;
end;
// 虽然 这样也可以 但是存在一些缺陷:
A. 导致运行时时间成本的增加,由string的动态增长性质确定
B. 在使用指针类型转换时,采取这种形式可能会出错或者转换不正确。
当然,这样定义也是可以的: (3)
type PersonRec = record
pID: string[10];
pName: string[10];
end;
但是这也会导致当指针类型转化时,会转换错误。

3. 多个if else if ..else分支时,请尽量用case of进行代替,后者的效率更高。
4. 当需要对某个函数的返回值做多次分支判断、多次存取时,应该用局部变量储存其返回值,比如应该:
I := FuncA;
if I > 10 then
else if I > 5 then
else ….
而不是
if FuncA >10 then
else if FuncA > 5 then

这样会多次存取,使得效率低下,甚至可能出现错误。
5. 判断的时候尽量减少判断的复杂度 比如在OnKeyPress判断一个字符是否为单引号,请直接如下判断:
if Key = ‘’’’ then // …或者为 if Key = #39 then
而绝不是:
if inttostr(ord(key))='39' then
// 这样多转了两个弯,极大的浪费了时间,虽然时间很少,但是请记得,我们的目标 还包括高效率性。
6. 如果函数返回值为Boolean型的,请不要定义为string型,然后以’true’,’false’这样的形式进行返回,这样不仅效率低下,还可能导致大小写不匹配的错误,坚决避免。
7. 动态Create出来的对象,除TForm的Create(Application)外,请手动用Free释放,以免内存泄漏。
8.

四. 可扩充性
1. 分支执行语句请尽量以 begin end括起来,比如
if a > 0 then
begin

end
else
begin

end;
即使只有一句执行代码,因为可能在将来的版本中会增加处理代码,这样会方便将来。
2. 分支执行语句请考虑条件状态的扩充 比如数据库某个字段的现有状态为’0’,’1’
为了考虑扩充性,下面的写法不妥:
if FieldByName(‘aaa’).AsString = ‘0’ then
//…
else
//…
因为可能将来会增加一个新状态’2’,那么到时候就很难知道当前的else指的是哪种状态,而这么写则比较合适:
if .. = ‘0’ then
//
else if .. = ‘1’ then
// ..

3.
五. 一些习惯规则:
1. 用户删除数据时,请尽量给予确认信息。
2. 用户修改、新增一条数据后,请尽可能定位到当前操作的记录,成功删除数据后,请尽可能定位到当前操作的下一条记录。
3.


六. 一些基本的API函数
1. ZeroMemory, FillChar
比如 rec为一个record类型的变量(非指针类型),初始化可以用
ZeroMemory(@rec, SizeOf(rec)) 或 FillChar(rec, SizeOf(rec), 0); 而不需要用单独为 其每个成员初始化的形式,比如 rec.a := 0;rec.b := ‘’;这样效率比较低下,如果还想 有特殊的初始化 可以这样 ZeroMemory, FillChar之后 rec.a := 1;
2. StrCopy, StrCopy(Dest: PChar; const Source: PChar): PChar;
Buffer: PChar;
Arr: array [0..10] of char;
GetMem(Buffer,Length(Label1.Caption) + 1);
StrCopy(Buffer, PChar(Label1.Caption));
StrCopy(Arr, Pchar(‘abcdef’));
3.
七.
beyondtkl 2005-01-12
  • 打赏
  • 举报
回复
比較新得。。沒怎麼寫了。。。

设计、编程规范
本规范粗略确定一些具体编程中的规范,我们编程首先看重的是能够运行起来,而且是安全的运行,然后是可读性、可维护性、可移植性,其次是高效率性,最后是可扩充性。我们在具体编程过程中,应该尽量考虑是否安全的运行,是否能很容易的让人理解,是否为高效的代码,绝不能只是简单的实现了当前的功能而已。

本规范列出了具体开发过程中可能出现的错误,请大家补充。

一. 安全性的编程
0. 我们自己书写的函数、过程,应当尽可能的被客户端安全的调用,即使客户端是错 误的调用,所以就要求对函数(过程)的参数进行足够的判断。
1. 防止数组越界,注意数组的下标以及上限,使用Low,High确定其下标及上限。
2. 使用指针,对象时最好先判断其是否为空,使用完后,请记得在必要的时候释放其所指向的空间,并重赋值为nil,使用方法为GetMem/FreeMem, New/Dispose配对。
3. 防止使用可能被优化的数据
比如 for I := 0 to 100 do
begin // 循环代码 end;
J := I; // 注意:此处的I的值不一定就是101,因为I可能被优化,所以这种风格 是不安全的,而万一出现问题,则是非常隐蔽的BUG,安全的形式是以另外一个变量 同时进行增加。
4. 定义变量,函数返回值请尽量先初始化,防止变量使用前没进行有意义的初始化,包括自定义的变量以及函数的返回值。
5. 字符串注意空格,确定是否保留空格,是否截空等处理,还应当注意数据库中的数据类型是否为char,varchar(varchar2) 尤其是在字符串的比较的时候需要注意空格,有时需要截取空格,有时需要加上空格,请多注意。
6. 字符NULL,包括不同数据库的具体意义,实现以及Delphi前台的意义,需要注意。
7. 浮点数的比较不一定可靠,因为浮点数的实现跟机器相关,不同的机器可能具有不同的精度。
8. 所有的循环操作注意结束条件,以及对控制变量的处理,比如在数据集的循环处理时,请记得写AdoQry.Next,以避免死循环。
9. 当类型转换时,需要考虑如果转换不成功时的处理,比如StrToInt(a); 如果转换不成功的话,那么就会出现错误,所以这种情况,请尽量用StrToIntDef,StrToFloatDef等函数进行转换。
10. 注意数据的溢出可能,比如数据库中的主键为12位整型,能表达的数范围为10^12-1,如果我们用 StrToInt的话,那么可能就会出现数据的截断,因为10^12大于Integer所能表示的范围2147483647, 那么就可能发生截断从而主键重复的错误(虽然这种可能性比较少,但是请尽量避免错误),所以考虑可以使用StrToInt64,否则会出现这种非常难以发现的BUG。
11. 进行事务处理时,请不要在自己的事务处理中直接提交当前别的事务,否则这是非常难以发现的BUG,而且可能导致严重的错误,因为这种行为是在背后进行的,且无法预料,所以坚决避免。
12. 能用静态数组尽量用静态数组,使用动态数组之前请记得先SetLength,使用类似TList,TStringList之类的动态容器时,使用前,请用 .Create先构造分配空间,最后如果容器里面保存的是指针,还需要循环释放里面的指针所指向的空间,最后再.Free本容器,以免造成内存泄漏,注意我们一般使用的是Count属性,非Capacity属性。
13. 使用动态库之类的,请尽量用动态调用,避免出现如果客户端没有DLL就不能启动应用程序的情况,增强健壮性。
14. 可能出错的代码请尽量用try except end异常处理保护起来, 并考虑尽可能的记载下来,进行恢复,尤其当与数据库交互时,所有访问点请尽量用try, except, end保护起来,并对不同的错误代码进行不同的处理,比如与数据库的连接中断等,如果遇到这种情况,就一定要处理好。
15. Timer的优先级比较低,所以其响应函数代码不一定能得到及时的执行,如果需要执行比较重要的代码,请尽量用单独的线程进行处理。
16. 类似Edit1.SetFocus这样的语句,请保证Edit1的Enable,Visible的属性为True,否则会出现错误。
17. 输入框尽量使得输入的有效性,一般都需要确定输入框的输入范围,比如只允许为数字,只允许为字母等等,这些应该写为一个专门的过程,供在OnKeyPress中调用,另外应该还限制输入框的输入长度,避免出现插入到数据库时,字段过长。
18. 与数据库交互原则,请尽可能的在前台检验数据的正确性,不能只放到数据库中去校验,这样减少与数据库交互次数、提高数据库性能,且不会过多的影响用户心情。
比如数据库中规定 某个字段的值的范围为 [0,100],如果输入101,应该在前台就要 提示,而不要等到真正的保存动作再校验、提示。
19.


二. 可读性、可维护性、可移植性
1. 模块,单元应该有对整体的说明信息,重要函数、过程、变量尽量有有意义的注释信息,且注意区分大小写。
2. 事件响应代码,业务处理代码请尽量以函数,过程进行封装,且函数过程的代码不要过长,即:函数,过程的功能应该尽可能简单、单一,以具有比较好的可维护性以及重用性。
3. 尽可能的声明为函数,且返回有意义的值。当然,如果函数体不可能出现某种异常的话,那么可以声明为过程即可。
4. Form,Unit,函数,过程间尽量以函数(过程)参数的形式进行传递,不能以Form的公有变量(数据)进行直接绑定,这样会增加模块间的耦合度,使得具有更差的可移植性,可维护性。
5. 变量,过程名,函数名,结构体等的命名尽量有意义,且符合规范。
6. 功能相似的代码请尽量抽象为过程、函数,提高代码的重用度以及维护性。
7. 数据,数据结构定义,业务逻辑处理请尽量抽象分开保存到另外单独的.pas单元中,即前台控制与业务处理尽量分开。
8. 可以考虑使用更有意义的状态代替某些初始状态,比如数据库中0代表男性,1代表女性,那么我们可能这样的枚举方式进行代替:
type SexFlag = ( sMale = 0, sFemale = 1 ); 从而这样更具有意义,增强可读性,并 增强了独立性。
9. 尽量提供有意义、合适的提示信息。
10. 代码行请不要写太长,基本上就是一个屏幕的宽度,使得阅读起来更方便,请尽量注意源码的格式化。
11. 尽量避免出现纯粹的数字,比如 if I > 10, 10这个数字,如果它是表示某个关键的控制变量,请用有意义的变量名表示,比如nMaxLenOfSome的形式,或者以良好的文档、注释进行辅助说明,不然别人就不知道这个10代表的意义,难以维护。
12. 注意代码行中空行的处理,一般空行表示上下的代码处理为较大的差异,或者可能出现较重要的处理,以示注意,所以代码行中该换行(空行)的时候就需要换行,以便更好的阅读。
13.
beyondtkl 2005-01-12
  • 打赏
  • 举报
回复
結貼...
chinaandys 2005-01-12
  • 打赏
  • 举报
回复
收藏!

支持

谢谢
CDSoftwareWj 2005-01-12
  • 打赏
  • 举报
回复
http://community.csdn.net/Expert/TopicView3.asp?id=3521017

再加上这个也不错 hehe^^

王婆卖瓜搂~~~
sunkevin 2005-01-12
  • 打赏
  • 举报
回复
可以收藏起来
boatzm 2005-01-12
  • 打赏
  • 举报
回复
收藏!

支持
chenzhichao2008 2005-01-12
  • 打赏
  • 举报
回复
8. 可以考虑使用更有意义的状态代替某些初始状态,比如数据库中0代表男性,1代表女性,那么我们可能这样的方式进行代替:
type SexFlag = ( sMale = 0, sFemale = 1 ); 从而这样更具有意义,增强可读性,并 增强了独立性。
chenzhichao2008 2005-01-12
  • 打赏
  • 举报
回复
最欣赏是这一个点

4. Form,Unit,函数,过程间尽量以函数(过程)参数的形式进行传递,不能以Form的公有变量(数据)进行直接绑定,这样会增加模块间的耦合度,使得具有更差的可移植性,可维护性
加载更多回复(19)

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧