1. 程式人生 > >函式設計的兩個原則(單一出口、一專多能)和例項

函式設計的兩個原則(單一出口、一專多能)和例項

函式設計應該像模組設計一樣,講究介面和封裝。函式的命名應該讓使用函式的程式設計師見名知意,函式應該封裝成簡單易用的形式,而且當函式內部實現演算法變化時,函式還能夠保持介面的穩定性。

下面的例子來源於浙江大學翁愷老師的《C語言程式設計進階》中的線性搜尋演算法。

首先看這樣一個搜尋演算法,實現的功能是在一個數組中找出需要的數字,並且返回該數字在陣列中的位置;找不到,則返回-1。

int search(int key,int a[],int len)
{
int ret=-1;    //這個是函式的輸出介面,返回-1則表示沒有找到;返回非-1的陣列則表示對應元素的下標
for(int i=0;i<len;i++){    //int i寫在for語句中是C99的寫法,編譯器如果不支援C99,則需要寫在for外面
	if(key==a[i]){
		ret=i;
		break;
	}
} 
return ret;
}

這裡,ret就是程式的輸出介面,無論內部函式演算法如何變化,始終保證介面的易用性,對使用該函式的程式設計師封裝其內部複雜性。這個函式是比較好的。

然後有人提出這樣一種函式的寫法:

int search(int key,int a[],int len)
{
int ret=-1;    //這個是函式的輸出介面,返回-1則表示沒有找到;返回非-1的陣列則表示對應元素的下標
for(int i=0;i<len;i++){
	if(key==a[i]){
		return i;
	}
} 
return -1;
}

當找到對應元素時,直接返回位置i;找不到,返回-1.

這裡違反了函式或者模組設計的原則:單一出口原則

。單一出口原則可以使得函式或者模組時非常清晰的,以後如果需要調整,只需要在函式內部調整即可,對於已經使用該函式的程式設計師來說會有極大的便利。

還有一種寫法如下:

int search(int key,int a[],int len)
{
int ret=-1;    //這個是函式的輸出介面,返回-1則表示沒有找到;返回非-1的陣列則表示對應元素的下標
for(int i=0;i<len;i++){
	if(key==a[i]){
		break;
	}
} 
	if(i==len)
	{
		return -1;
	}
	else{
		return i;
	}
}

思路是首先看能否找到搜尋的元素,找不到,則i=len,返回-1;找到的話,則會直接在第一個if語句進行break,然後轉入下面的else語句,返回找到的位置。這個函式看起來好像也沒有問題,但是違反了函式設計的另一個原則:不要一專多能。變數i承擔了兩個功能,不僅用來遍歷,還用來表示到底有沒有找到搜尋元素。所以,一專多能是不好的程式碼。

這樣回頭來看,往往在函式裡面可以單獨設定函式的輸出介面。