信息安全案例教程:技術(shù)與應(yīng)用 第2版 課件 第7章 面向?qū)ο蟮某绦蛟O(shè)計_第1頁
信息安全案例教程:技術(shù)與應(yīng)用 第2版 課件 第7章 面向?qū)ο蟮某绦蛟O(shè)計_第2頁
信息安全案例教程:技術(shù)與應(yīng)用 第2版 課件 第7章 面向?qū)ο蟮某绦蛟O(shè)計_第3頁
信息安全案例教程:技術(shù)與應(yīng)用 第2版 課件 第7章 面向?qū)ο蟮某绦蛟O(shè)計_第4頁
信息安全案例教程:技術(shù)與應(yīng)用 第2版 課件 第7章 面向?qū)ο蟮某绦蛟O(shè)計_第5頁
已閱讀5頁,還剩46頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

第7章面向?qū)ο蟮某绦蛟O(shè)計信息學(xué)院2024引言7.1案例:模擬乒乓球比賽7.2類和對象實例7.3面向?qū)ο蟮幕咎匦?.4面向?qū)ο蟮某绦蛟O(shè)計過程7.5編程實踐:tkinter中的彈出框7.6本章小結(jié)7.7習(xí)題在章首案例的指引下,本章將深入學(xué)習(xí)面向?qū)ο蟪绦蛟O(shè)計思想,其中發(fā)現(xiàn)并定義類是最基礎(chǔ)也是最重要的。在編程實踐中,還將學(xué)習(xí)如何用彈出對話窗口來處理輸入和輸出。7.1案例:模擬乒乓球比賽對象的概念更符合現(xiàn)實世界中的復(fù)雜情況,每個對象既有靜態(tài)的屬性,也有動態(tài)的行為。作為一名乒乓球賽選手,他(她)有自己的技能水平,可以在一場比賽中發(fā)球、得分。運行程序,出現(xiàn)消息提示框,對模擬情景進行簡要介紹。點擊“確定”后,出現(xiàn)獲取輸入的對話框。如果用戶輸入的數(shù)據(jù)非法,出現(xiàn)消息提示框,用戶重新輸入。也可以點擊“Cancel”退出程序。輸入0.6、0.5、10000,模擬結(jié)果顯示在消息提示框里。7.1案例:模擬乒乓球比賽在面向?qū)ο蟪绦蛟O(shè)計中,程序被分解為若干個類,面向?qū)ο蟮某绦蛟O(shè)計過程就是發(fā)現(xiàn)并定義一系列類的過程。7.2類和對象實例7.2.1類的定義在面向?qū)ο蟪绦蛟O(shè)計中,我們需要根據(jù)問題來定義自己的類,而不僅僅是使用別人定義好的類。使用關(guān)鍵詞class來定義類,其一般形式如下:class<class-name>():def__init__(self,<formal-parameters>):self.<attribute-name>=<value>…def<method-name>(self,<formal-parameters>):<statements>…7.2.1類的定義<class-name>就是類的名字,命名規(guī)則和變量、函數(shù)一樣,習(xí)慣上為了區(qū)分,類名的首字母一般大寫。類的定義里面包含若干方法的定義,方法的定義和函數(shù)的定義類似。不同的是方法的第一個形參都是self,即使沒有任何其他形參,也需要有這個參數(shù),它有著特殊的含義,指向?qū)ο笞陨?。有了這個參數(shù),在定義任何方法的時候都可以訪問對象的屬性(self.<attribute-name>)或者其他方法(self.<method-name>)。7.2.1類的定義類中定義的第一個方法是初始化方法__init__(),每次根據(jù)類創(chuàng)建對象實例的時候都會調(diào)用這個方法,通常用來對類所包含屬性的初始化賦值。這些屬性的值可以通過調(diào)用其他方法來進行改變或者獲取,從而使得對象的屬性在對象實例存續(xù)期間都是可見的,而不僅僅限于某個方法。類所包含的屬性一般并不是直接可見的,可以通過調(diào)用方法來獲取或修改屬性的值。這種特性叫做封裝性(encapsulation)?!纠?-1】定義課程類Course在初始化方法中,定義屬性self.courses,初始化為空列表,該列表將記錄多門課程的名稱、學(xué)分和成績。定義一個從用戶那里獲取課程名稱、學(xué)分和成績的方法,命名為get_input()

,self.courses的值被修改。再定義一個輸出課程信息的方法print_courses(),課程名稱、學(xué)分和成績之間用制表符分隔?!纠?-1】定義課程類Course接下來定義幾個用來進行數(shù)據(jù)統(tǒng)計的方法,分別是統(tǒng)計課程門數(shù)的total_courses()、統(tǒng)計總學(xué)分的total_credits()、計算GPA的gpa()。這幾個方法中都訪問了self.courses。在gpa()方法中還調(diào)用了另一個方法total_credits()?!纠?-1】定義課程類Course將對CSV文件的訪問獨立出來,分別定義write_csv()方法和read_csv()方法來完成課程信息的寫入和讀取功能。無論是寫入還是讀取,都訪問了屬性self.courses。是否將課程信息存入CSV文件取決于是否調(diào)用這兩個方法。7.2.1類的定義現(xiàn)實世界中的對象往往都可以定義成類,比如每個人都是一個對象,可以為所有人定義一個類。本章案例模擬現(xiàn)實世界中的乒乓球比賽,比賽選手也是對象,我們可以為選手定義一個類,命名為Player。首先考慮為了模擬比賽,選手類需要有哪些屬性呢?基本屬性就是他(她)的技能水平(self.prob),還有他(她)參加比賽時的得分(self.score)以及在一場比賽中他(她)已經(jīng)發(fā)了多少次球(self.serve)。7.2.1類的定義fromrandomimportrandomclassPlayer:def__init__(self,prob):self.prob=prob#技能水平self.score=0#比賽得分self.serve=0#發(fā)球次數(shù)defwinServe(self):returnrandom()<=self.prob初始化方法為屬性賦初值。除self之外,還有一個形參prob,初始化時將其賦值給對象的屬性self.prob。定義winServe(),根據(jù)選手的技能水平來模擬在一次發(fā)球中能否贏得一分。7.2.1類的定義defincScore(self):self.score=self.score+1defincServe(self):self.serve=self.serve+1defgetScore(self):returnself.scoredefgetServe(self):returnself.serve定義incScore()和incServe()方法來對比賽得分和發(fā)球次數(shù)進行累加。定義getScore()和getServe()方法來返回某個時刻的比賽得分和發(fā)球次數(shù)。本章案例的初步版本形成,將程序文件保存為ch07.py,運行程序,如果有錯誤則進行修正。試一試7.2.2對象實例類只是一個模板,我們需要根據(jù)類來創(chuàng)建一個具體的對象,對這個對象進行操作,這個過程就是實例化。實例化過程其實就是調(diào)用類的初始化方法__init__()來構(gòu)造一個對象,但與調(diào)用其他方法不同,我們使用類名而不是方法名來調(diào)用?!纠?-2】在IDLE中創(chuàng)建Course類的實例從course模塊引入Course類。用Course類名調(diào)用初始化方法來構(gòu)造一個對象實例并賦值給變量stud_course,用這個變量來記錄某個學(xué)生所學(xué)課程的名稱、學(xué)分和成績。調(diào)用get_input()方法來獲取課程信息調(diào)用print_courses()方法查看課程信息調(diào)用total_courses()、total_credits()和gpa()調(diào)用write_csv()方法將課程信息存入CSV文件中【例7-2】在IDLE中創(chuàng)建Course類的實例重新啟動Shell,再次創(chuàng)建Course類的對象實例并賦值給stud_course,此時調(diào)用print_courses()方法可以看到?jīng)]有任何課程信息,因為這是一個新的被初始化的對象變量。調(diào)用get_input()方法獲取課程信息調(diào)用write_csv()方法將課程信息存入文件調(diào)用total_courses()、total_credits()和gpa()調(diào)用read_csv()方法讀取課程信息調(diào)用print_courses()方法,看到上一次和這一次輸入的課程信息7.2.2對象實例本章案例中,我們已經(jīng)定義好了選手類Player,下面在IDLE解釋器中創(chuàng)建其對象實例并進行操作。從ch07模塊引入Player類。>>>fromch07importPlayer然后用Player類名調(diào)用初始化方法來構(gòu)造一個對象實例并賦值給變量playerA,其技能水平為0.6。>>>playerA=Player(0.6)比賽剛開始時playerA先發(fā)球,調(diào)用incServe()方法增加一次發(fā)球。>>>playerA.incServe()7.2.2對象實例調(diào)用winServe()方法來模擬一次playerA發(fā)球時能否贏得一分,結(jié)果為False,不得分。>>>playerA.winServe()False接下來仍然是playerA發(fā)球,調(diào)用incServe()方法再增加一次發(fā)球,。>>>playerA.incServe()7.2.2對象實例調(diào)用winServe()方法再模擬一次,結(jié)果為True,調(diào)用incScore()方法增加一分。>>>playerA.winServe()True>>>playerA.incScore()最后調(diào)用getServe()和getScore()方法觀察當(dāng)前playerA的發(fā)球次數(shù)和得分情況,分別為2和1。>>>playerA.getServe()2>>>playerA.getScore()1一場乒乓球比賽需要兩位選手,再創(chuàng)建另一個選手對象playerB,繼續(xù)至少兩個回合的比賽,觀察雙方的發(fā)球次數(shù)和得分情況。試一試面向?qū)ο蟮幕咎卣靼ǚ庋b性、繼承(inheritance)和多態(tài)性(polymorphism),其中多態(tài)性和繼承密切相關(guān)。7.3面向?qū)ο蟮幕咎匦?.3.1封裝性封裝把“what”和“how”區(qū)分開,在使用對象時我們只需要知道它是什么(即“what”),并不需要知道它是怎么實現(xiàn)的(即“how”)。當(dāng)我們使用別人定義的類或函數(shù)的時候,很容易理解什么是封裝性,因為我們并不知道這些類或函數(shù)的實現(xiàn)細(xì)節(jié)。在使用自己定義的類或函數(shù)的時候,我們既知道它是什么,也知道它是怎么實現(xiàn)的,但是仍然要區(qū)分開實現(xiàn)和使用。7.3.1封裝性將實現(xiàn)和使用分離,只要外部接口不變,內(nèi)部實現(xiàn)細(xì)節(jié)如何變化也不會影響外部的使用。封裝性的另一個好處就是支持代碼重用(codereuse),我們在一個模塊里定義的類,可以很方便地在其他模塊中引入,而無需重復(fù)寫一遍代碼,對類的定義修改了,所有引入它的模塊都修改了。對象之間的交互就是消息的傳遞。調(diào)用對象的方法就是給這個對象發(fā)送一條消息,請求它按照這個方法的功能執(zhí)行相應(yīng)的操作。【例7-3】定義Person類記錄人的ID、姓名、出生地等信息,并定義一個用來進行自我介紹的方法self_intro()

。一般做自我介紹時,不會介紹ID,所以單獨定義一個返回ID的get_id()方法。創(chuàng)建Person類的對象實例并賦值給變量personA,初始化過程傳遞了相應(yīng)的屬性值作為參數(shù),然后給personA發(fā)送一條消息,請他(她)做自我介紹。7.3.1封裝性這個例子中可以這樣理解封裝性,在main()函數(shù)中并不知道Person類是如何定義的,也不知道它有哪些屬性,但知道要用什么參數(shù)來構(gòu)造一個對象實例(初始化方法的外部接口),也知道有一個self_intro()方法可供調(diào)用,但并不知道這個方法是如何進行自我介紹的。對self_intro()方法內(nèi)部實現(xiàn)細(xì)節(jié)的修改,并不影響main()函數(shù)對它的調(diào)用。7.3.2繼承和多態(tài)性在定義一個類時,可以從已有的類中繼承其屬性和方法,這個新定義的類稱為子類(subclass),被繼承的類稱為父類(parentclass)或超類(superclass)。利用繼承關(guān)系,子類無需重復(fù)定義父類中已有的屬性和方法,也有利于代碼重用。定義繼承關(guān)系的形式如下:class<sub-class-name>(<parent-class-name>):我們可以基于Person類來定義Player類,使得Player類能夠繼承Person類中定義的所有屬性和方法。7.3.2繼承和多態(tài)性frompersonimportPersonclassPlayer(Person):def__init__(self,iden,name,birth,prob):Person.__init__(self,iden,name,birth)self.prob=prob#技能水平self.score=0#比賽得分self.serve=0#發(fā)球次數(shù)…defmain():

playerA=Player('01','ZhangSan','Beijing',0.6)

playerA.self_intro()if__name__=="__main__":main()在括號內(nèi)加上父類的名字Person,就可以繼承來自于Person類的屬性和方法了。初始化一個選手對象時也需要傳遞Person類的屬性值作為參數(shù)。首先調(diào)用父類的初始化方法,并將參數(shù)傳遞給它。創(chuàng)建一個選手對象時,除技能水平外,也傳遞了ID、姓名、出生地的參數(shù)值。7.3.2繼承和多態(tài)性Player類中并沒有重復(fù)定義Person類中的屬性和方法,而是通過繼承自動獲得,提高了效率,結(jié)構(gòu)上也更加層次分明,易于理解。上例中子類的對象直接繼承了父類中定義的方法并調(diào)用了它,實際上子類還可以對父類中定義的方法進行重寫,以滿足自身特殊化需求。如果一個父類有多個子類,這些子類可以對從父類繼承來的同一個方法進行重寫,也就是同一個方法在父類和不同的子類中實現(xiàn)代碼不同,這種特性就稱為多態(tài)性?!纠?-4】定義學(xué)生類Student定義一個獲取學(xué)號的方法get_stu_id()。重寫父類中定義的self_intro()方法,除了基本信息介紹外,還增加了學(xué)生信息的介紹。創(chuàng)建一個學(xué)生對象stud,傳遞基本信息和學(xué)生信息,調(diào)用子類中重寫的self_intro()方法,調(diào)用父類中的get_id()方法和子類中的get_stu_id()方法。定義Person類的另一個子類:教師類Teacher,用來記錄教師的工號、學(xué)校、學(xué)院等信息,重寫Person類的self_intro()方法,使其包含教師信息。試一試面向?qū)ο蟮某绦蛟O(shè)計過程就是發(fā)現(xiàn)并定義一系列類的過程。7.4面向?qū)ο蟮脑O(shè)計過程序號步驟說明(1)尋找候選對象從問題描述開始仔細(xì)分析,對象通常是名詞,且具有較為復(fù)雜的屬性和行為(2)識別屬性識別對象所包含的信息,一些屬性可以用簡單的數(shù)據(jù)類型表示,另一些則可能指向復(fù)雜的對象/類(3)設(shè)計接口對象類需要哪些操作,問題描述中有哪些描述行為的動詞,列出類所需要的方法(4)設(shè)計重要方法采用自頂向下、逐步求精的方法對較為復(fù)雜的方法進行詳細(xì)設(shè)計,進一步分解(5)不斷迭代設(shè)計過程并非是線性的,設(shè)計新類、給現(xiàn)有類添加屬性和方法都是不斷迭代的(6)嘗試替代方案好的設(shè)計都是不斷試錯(tryanderror),不要害怕放棄不可行的方案,也不要害怕嘗試新的想法7.4.1尋找候選對象本章案例的問題描述是:模擬兩位選手之間的很多場比賽,看看最終各勝負(fù)多少場。不難發(fā)現(xiàn),“比賽”、“選手”都是關(guān)鍵的名詞,將它們作為對象進行設(shè)計。同時,要模擬很多場比賽,并對結(jié)果進行統(tǒng)計,這個動作是“比賽”和“選手”無法完成的,因此,將“統(tǒng)計結(jié)果”也作為對象進行設(shè)計。解決問題的思路是:兩位有著各自技能水平的選手打比賽,每打完一場比賽,就更新統(tǒng)計結(jié)果,打完N場比賽后輸出最終統(tǒng)計結(jié)果。7.4.2設(shè)計并定義類選手類Player我們已經(jīng)設(shè)計并定義好了,其中所有方法的設(shè)計和實現(xiàn)代碼都非常簡單。下面來設(shè)計并定義比賽類Game和統(tǒng)計結(jié)果類SimStats,需要說明的是,設(shè)計過程也是不斷迭代和不斷試錯的,這里呈現(xiàn)的是最終設(shè)計結(jié)果。Game類“比賽”有哪些屬性呢?首先需要兩位選手,其次是每一個回合發(fā)球方是誰,根據(jù)乒乓球計分規(guī)則,發(fā)球方輸球,對手方要得分。classGame:def__init__(self,probA,probB):#初始化一場比賽self.playerA=Player(probA)self.playerB=Player(probB)self.server=self.playerA

self.opponent=self.playerB構(gòu)造一個Game對象需要傳遞的參數(shù)就是雙方選手的技能水平probA和probB。self.playerA和self.playerB都是Player對象,初始化時傳遞的參數(shù)是技能水平。假設(shè)總是self.playerA先發(fā)球,那么對手方就是self.playerB。Game類“比賽”中最重要的操作就是“打”了,定義play()方法,采用自頂向下的方法進行進一步分解。defplay(self):whilenotself.isOver():self.checkServer()self.server.incServe()ifself.server.winServe():self.server.incScore()else:self.opponent.incScore()“打”的過程需要循環(huán),終止條件是比賽結(jié)束,分解出isOver()方法來進行判斷。每個回合都需要確定誰發(fā)球,分解出checkServer()方法來確定。發(fā)球方的發(fā)球次數(shù)累加一次,如果贏了則得一分,否則對手方得一分。Game類defisOver(self):

a,b=self.getScores()returnabs(a-b)>=2and(a>=11orb>=11)defgetScores(self):returnself.playerA.getScore(),self.playerB.getScore()根據(jù)雙方選手的得分來判斷比賽是否結(jié)束,設(shè)計并調(diào)用Game類的getScores()方法來獲取雙方選手的得分。分別調(diào)用兩位選手的getScore()方法。Game類defcheckServer(self):

a,b=self.getScores()ifabs(a-b)<2and(a>10orb>10):#如果是10平之后self.changeServer()elifself.server.getServe()%2==0andself.server.getServe()!=0:self.changeServer()defchangeServer(self):ifself.server==self.playerA:self.server=self.playerBself.opponent=self.playerAelse:self.server=self.playerAself.opponent=self.playerB如果是10平之后,每發(fā)一個球都換發(fā),否則發(fā)球方累計發(fā)球次數(shù)為偶數(shù)且不為0時換發(fā)。分解出changeServer()方法來完成換發(fā)球。Simstats類“統(tǒng)計結(jié)果”的屬性就是雙方選手各贏了多少場。classSimStats:def__init__(self):self.winsA=0self.winsB=0Simstats類“統(tǒng)計結(jié)果”中最重要的操作就是“更新”了,定義update()方法,根據(jù)一場比賽的結(jié)果來更新統(tǒng)計結(jié)果。defupdate(self,aGame):

a,b=aGame.getScores()ifa>b:#選手A贏了self.winsA=self.winsA+1else:#選手B贏了self.winsB=self.winsB+1defgetResult(self):returnself.winsA,self.winsB形參aGame是一個Game對象。調(diào)用其getScores()方法獲取一場比賽結(jié)束后雙方的得分。定義一個返回統(tǒng)計結(jié)果的方法getResult()。simpledialog和messagebox是tkinter中的兩個包,前者用來彈出輸入對話框,后者用來彈出消息對話框。fromtkinterimportsimpledialog,messageboxsimpledialog包的常用函數(shù):7.5編程實踐:彈出對話框函數(shù)功能askfloat(title=None,prompt=None)從用戶那里獲取一個小數(shù),若不是,提示“非法值”,要求用戶重新輸入askinteger(title=None,prompt=None)從用戶那里獲取一個整數(shù),若不是,提示“非法值”,要求用戶重新輸入askstring(title=None,prompt=None)從用戶那里獲取一個字符串,若不是,提示“非法值”,要求用戶重新輸入7.5編程實踐:彈出對話框函數(shù)功能showerror(title=None,message=None)打開一個錯誤提示對話框showinfo(title=None,message=None)打開一個信息提示對話框showwarning(title=None,message=None)打開一個警告提示對話框askyesno(title=None,message=None)打開一個“是/否”對話框,返回True或Falseaskretrycancel(title=None,message=None)打開一個“重試/取消”對話框,返回True或Falsemessagebox包的常用函數(shù):【例7-5】修改Course類定義的輸入輸出分別調(diào)用simpledialog中的askstring()和askinteger()函數(shù)接收課程信息輸入。詢問用戶是否繼續(xù)輸入調(diào)用messagebox中的askyesno()函數(shù)。將所有要輸出的字符串合并在變量info中,然后將其作為參數(shù)調(diào)用messagebox中的show

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論