爲了對類有一個更加清晰的認識,我們應該深入一下並嘗試構建一個較複雜的類
1·我們先從分析問題開始吧。
矩形“Rectangle”對象將具有以下字段:
—height是保存矩形高度的長度字段
—width是保存矩形寬度的寬度字段
-------------------------------------
矩形類還將具有以下方法:
—get_perimeter(獲取參數),用於計算形狀外部周圍的距離(周長)
— is_square是一個檢查我們的實際矩形是否爲正方形的方法(如果寬度等於高度,那麼就是正方形)
—get_area是一個返回矩形面積的方法(就是height 乘 width的結果,矩形面積公式長乘寬)
—get_width此方法將返回對象寬度“width”字段中的值。
—get_height此方法將返回對象高度“height”字段中的值。
以上就是我們需要實現的全部方法
2·接下去我們應該使用UML圖(統一建模語言圖表)
可以看到以下一組標準圖表,可以方便地以圖形方式描述面向對象的系統:
第一行:類的名稱
第二行:屬性
第三行:方法
我們需要在每個元素的前面加上一個加號和減號以表示該元素是私有還是公有,大多數情況下在屬性名稱之後,還可以指定屬性本身的類型。
在方法名稱後面,不僅可以指定返回元素的類型,還可以在括號之間指定該方法是否接受任何屬性,如果可以接受,那麼屬性應該是哪種。
我們把UML圖應用到之前分析過的矩形上面:
可以看到它的名字是Rectangle,它有兩個屬性,height和width,都是浮點數。並且有五種方法,除了is_square返回布爾值(true或false),其它都是浮點數。
但是這個圖表有一個錯誤,我們少了正負號
所以應該在第二排的前面都加上“-”,我們要保密我們的屬性;在第三排裏面全部加上“+”,因爲我們希望方法可以從外部訪問,以便讓代碼的其餘部分和用戶能夠與類和對象交互。
3·開始編寫類字段的代碼
當我們創建一個類時,我們需要輸入class,類的名稱和冒號來實例化;創建類時最重要的事情是初始化方法(init方法:開頭和結尾有兩個下劃線)
class Rectangle:
def __init__(self, h, w):
self.__height = h
self.__width = w
要記住使用的“self.”,這是希望我們的方法知道引用的是特定的這個Rectangle類的實例。並且我們必須在height和width之前加上兩個下劃線來確保它是私有屬性。
init創建類的一個新實例並將這個對象賦給本地變量
我們可以根據通用的類(餅乾模具)創建對象(餅乾):
self參數指的是對象的實例,在創建實例時分配的局部變量在這個例子中是h和w。
類可以具有稱爲__init__函數的特殊方法
----- __init__是在創建對象時自動調用的方法;
----- __init__用於在創建對象時執行操作;
----- __init__通常初始化實例字段並執行其他對象初始化任務。
你可以看到我們不止有剛纔描述的init方法,還有別的方法get_width和get_height:
class Rectangle:
def __init__(self, h, w):
self.__height = h
self.__width = w
def get_width(self): #我們把self傳給方法,我們不傳遞任何屬性或參數,只是傳遞對象自己給方法
return self.__width
def get_height(self):
return self.__height
4·爲矩形類編寫更多方法
之前分析的五個方法全寫進去:
class Rectangle:
def __init__(self, h, w):
self.__height = h
self.__width = w
def perimeter(self):
return (2 * self.__height) + (2 * self.__width)
def area(self):
return self.__height * self.__width
def isSquare(self):
return (self.__height == self.__width)
def get_width(self):
return self.__width
def get_height(self):
return self.__height
可以根據之前寫的一一對應,都在內部傳遞,看起來很清楚。
5·創建矩形對象
如果我們要從類中實例化一個對象,我們可以:
這意味着box現在是Rectangle對象,我們可以在類的方法中使用box變量。
box變量保存矩形對象的地址(如果我們打印box,Python會告訴我們box是一個Rectangle對象,存儲在一個特定的地址和內存中),然而我們知道在我們的box中,我們有由寬和高參數組成的Rectangle對象。
6·爲矩形類編寫賦值函數方法
先來看看類的訪問器和變異器方法:
由於我們使用私有變量遇到了數據隱藏的概念,類中的字段是私有的。
檢索字段數據的方法稱爲訪問器accessor(我們之前實現的那些方法,它們進入一個對象並返回一個存儲在該對象中的值)
修改字段數據的方法稱爲mutator(它們不僅進入也檢索值,也有能力接受改變它的值並改變它在對象方法中的存儲方式)
程序員希望其他類查看的每個字段都需要一個訪問器。(當我們想要什麼東西可見時,提供accessor方法可以讓用戶進來使用數據)
程序員希望被其他類修改的每個字段都需要一個變異器。(mutator允許其他類進入一個類並更改存儲的值)
那麼我們如何爲Rectangle類編寫一個mutator方法呢?
這裏的所有方法都是mutator方法
7·調用 setLength 方法
舉一個可視的例子,用點符號在box對象上調用set_height
結果是box變量保存矩形對象的地址,python進入了地址,搜索對象並存儲高度爲10.
這是執行set_height方法後box對象的狀態。我們沒有寬的值,但高度成了我們從外面傳遞的值。
8·對於Rectangle的例子,accessor和mutator是:
get_width,get_height是accessor;
set_width,set_height是mutator。
這些方法的其他名稱是getter和setter。(但這些只對數量,重要的是我們要理解:一個mutator方法能夠進入一個對象並改變存儲在其中的數據;一個accessor方法則訪問數據,不修改數據。)
9·將UML圖轉換爲代碼
回到我們的UML圖,我們現在需要更復雜的東西。
一旦測試了類結構,就可以編寫和測試方法主體。
這個圖少了正負號:
void意識是無意義,所以沒什麼返回的,但是它們會被傳遞。
class Rectangle:
def __init__(self, h, w):
self.__height = h
self.__width = w
def perim(self):
return (2 * self.__height) + (2 * self.__width )
def area(self):
return self.__height * self.__width
def isSquare(self):
return (self.__height == self.__width)
def get_width(self):
return self.__width
def get_height(self):
return self.__height
def set_width(self, w):
self.__width = w
def set_height(self, h):
self.__height = y
10·陳舊的數據
陳舊的數據可能有問題
創建一個返回動態運算的方法而不是用變量,可以避免在對象中出現陳舊數據的情況。
而不是在矩形類中使用區域變量:
在這種情況下,我們沒有變量包含面積的值,我們只有一個返回乘法結果的方法。
當調用這個方法時,它會動態地計算矩形區域的值。(所以更容易理解,我們用的變量少了一個。值是動態創建和返回的,而不是創建和存儲的,只是稍後再返回。)
現在,對height或width變量的任何更改都不會離開矩形的積。(stale就是:如果我們有一個area變量在計算矩形的面積,當我們改變寬度和高度的值時,除非我們重新開始計數area,否則我們無法更新它。這會導致面積值錯誤,依據於更改後的寬高值。)
11·類佈局約定
源代碼文件的佈局可能因需求者的不同而不同。
其中一個常見的佈局是字段首先列出(init方法放在第一位);第二列方法accessor和mutator通常分組(然後所有方法確保accessor和mutator組在一起,順序無關緊要,這樣當我們看類的時候能更容易認出發生了什麼。使代碼更加有條理秩序)
12·運行/測試 矩形類
現在我們來談談測試
box = Rectangle(3,5)
print ("Perimitar value is %.2f" %box.perim())
print ("Rectangle total area is %.2f" %box.area())
print (box.is_square())
print ("Rectangle height %.2f and width %.2f" %(box.get_height(), box.get_width()))
在這種情況下得出的結果:
我們類一切正常,因爲測試順利進行。
如果我們最終要使用某些mutator,我們可以將寬高度設置成一樣:
box.set_height(9)
box.set_width(9)
print ("Perimitar value is %.2f" %box.perim()) print ("Rectangle total area is %.2f" %box.area()) print ("is it a Square? : ", box.is_square()) print ("Rectangle height %.2f and width %.2f" %(box.get_height(), box.get_width()))
然後重新運行整個代碼程序來查看結果:
這裏面使用了mutator方法更改實例變量(高度和寬度)