面向對象的程序設計


一 面向對象的程序設計的由來

面向對象設計的由來見概述:http://www.cnblogs.com/linhaifeng/articles/6428835.html

面向對象的程序設計:路飛學院版

上海周末2期面向對象課件下載

二 什么是面向對象的程序設計及為什么要有它

面向過程的程序設計:核心是過程二字,過程指的是解決問題的步驟,即先干什么再干什么......面向過程的設計就好比精心設計好一條流水線,是一種機械式的思維方式。

優點是:復雜度的問題流程化,進而簡單化(一個復雜的問題,分成一個個小的步驟去實現,實現小的步驟將會非常簡單)

缺點是:一套流水線或者流程就是用來解決一個問題,生產汽水的流水線無法生產汽車,即便是能,也得是大改,改一個組件,牽一發而動全身。

應用場景:一旦完成基本很少改變的場景,著名的例子有Linux內核,git,以及Apache HTTP Server等。

 

面向對象的程序設計:核心是對象二字,(要理解對象為何物,必須把自己當成上帝,上帝眼里世間存在的萬物皆為對象,不存在的也可以創造出來。面向對象的程序設計好比如來設計西游記,如來要解決的問題是把經書傳給東土大唐,如來想了想解決這個問題需要四個人:唐僧,沙和尚,豬八戒,孫悟空,每個人都有各自的特征和技能(這就是對象的概念,特征和技能分別對應對象的數據屬性和方法屬性),然而這並不好玩,於是如來又安排了一群妖魔鬼怪,為了防止師徒四人在取經路上被搞死,又安排了一群神仙保駕護航,這些都是對象。然后取經開始,師徒四人與妖魔鬼怪神仙交互着直到最后取得真經。如來根本不會管師徒四人按照什么流程去取),對象是特征與技能的結合體,基於面向對象設計程序就好比在創造一個世界,你就是這個世界的上帝,存在的皆為對象,不存在的也可以創造出來,與面向過程機械式的思維方式形成鮮明對比,面向對象更加注重對現實世界的模擬,是一種“上帝式”的思維方式。

優點是:解決了程序的擴展性。對某一個對象單獨修改,會立刻反映到整個體系中,如對游戲中一個人物參數的特征和技能修改都很容易。

缺點:

1. 編程的復雜度遠高於面向過程,不了解面向對象而立即上手基於它設計程序,極容易出現過度設計的問題。一些擴展性要求低的場景使用面向對象會徒增編程難度,比如管理linux系統的shell腳本就不適合用面向對象去設計,面向過程反而更加適合。

2. 無法向面向過程的程序設計流水線式的可以很精准的預測問題的處理流程與結果,面向對象的程序一旦開始就由對象之間的交互解決問題,即便是上帝也無法准確地預測最終結果。於是我們經常看到對戰類游戲,新增一個游戲人物,在對戰的過程中極容易出現陰霸的技能,一刀砍死3個人,這種情況是無法准確預知的,只有對象之間交互才能准確地知道最終的結果。

應用場景:需求經常變化的軟件,一般需求的變化都集中在用戶層,互聯網應用,企業內部軟件,游戲等都是面向對象的程序設計大顯身手的好地方

面向對象的程序設計並不是全部。對於一個軟件質量來說,面向對象的程序設計只是用來解決擴展性。

選讀:程序設計思想發展史

三 類與對象

類即類別、種類,是面向對象設計最重要的概念,對象是特征與技能的結合體,而類則是一系列對象相似的特征與技能的結合體

那么問題來了,先有的一個個具體存在的對象(比如一個具體存在的人),還是先有的人類這個概念,這個問題需要分兩種情況去看

在現實世界中:先有對象,再有類

世界上肯定是先出現各種各樣的實際存在的物體,然后隨着人類文明的發展,人類站在不同的角度總結出了不同的種類,如人類、動物類、植物類等概念

也就說,對象是具體的存在,而類僅僅只是一個概念,並不真實存在

在程序中:務必保證先定義類,后產生對象

這與函數的使用是類似的,先定義函數,后調用函數,類也是一樣的,在程序中需要先定義類,后調用類

不一樣的是,調用函數會執行函數體代碼返回的是函數體執行的結果,而調用類會產生對象,返回的是對象

 

按照上述步驟,我們來定義一個類(我們站在老男孩學校的角度去看,在座的各位都是學生)

#在現實世界中,站在老男孩學校的角度:先有對象,再有類
對象1:李坦克
    特征:
        學校=oldboy
        姓名=李坦克
        性別=男
        年齡=18
    技能:
        學習
        吃飯
        睡覺

對象2:王大炮
    特征:
        學校=oldboy
        姓名=王大炮
        性別=女
        年齡=38
    技能:
        學習
        吃飯
        睡覺

對象3:牛榴彈
    特征:
        學校=oldboy
        姓名=牛榴彈
        性別=男
        年齡=78
    技能:
        學習
        吃飯
        睡覺


現實中的老男孩學生類
    相似的特征:
        學校=oldboy
    相似的技能:
        學習
        吃飯
        睡覺
在現實世界中:先有對象,再有類
#在程序中,務必保證:先定義(類),后使用(產生對象)
PS:
  1. 在程序中特征用變量標識,技能用函數標識
  2. 因而類中最常見的無非是:變量和函數的定義

#程序中的類
class OldboyStudent:
    school='oldboy'
    def learn(self):
        print('is learning')
        
    def eat(self):
        print('is eating')
    
    def sleep(self):
        print('is sleeping')
  


#注意:
  1.類中可以有任意python代碼,這些代碼在類定義階段便會執行
  2.因而會產生新的名稱空間,用來存放類的變量名與函數名,可以通過OldboyStudent.__dict__查看
  3.對於經典類來說我們可以通過該字典操作類名稱空間的名字(新式類有限制),但python為我們提供專門的.語法
  4.點是訪問屬性的語法,類中定義的名字,都是類的屬性

#程序中類的用法
.:專門用來訪問屬性,本質操作的就是__dict__
OldboyStudent.school #等於經典類的操作OldboyStudent.__dict__['school']
OldboyStudent.school='Oldboy' #等於經典類的操作OldboyStudent.__dict__['school']='Oldboy'
OldboyStudent.x=1 #等於經典類的操作OldboyStudent.__dict__['x']=1
del OldboyStudent.x #等於經典類的操作OldboyStudent.__dict__.pop('x')


#程序中的對象
#調用類,或稱為實例化,得到對象
s1=OldboyStudent()
s2=OldboyStudent()
s3=OldboyStudent()

#如此,s1、s2、s3都一樣了,而這三者除了相似的屬性之外還各種不同的屬性,這就用到了__init__
#注意:該方法是在對象產生之后才會執行,只用來為對象進行初始化操作,可以有任意代碼,但一定不能有返回值
class OldboyStudent:
    ......
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
    ......


s1=OldboyStudent('李坦克','',18) #先調用類產生空對象s1,然后調用OldboyStudent.__init__(s1,'李坦克','男',18)
s2=OldboyStudent('王大炮','',38)
s3=OldboyStudent('牛榴彈','',78)


#程序中對象的用法
#執行__init__,s1.name='牛榴彈',很明顯也會產生對象的名稱空間
s2.__dict__
{'name': '王大炮', 'age': '', 'sex': 38}

s2.name #s2.__dict__['name']
s2.name='王三炮' #s2.__dict__['name']='王三炮'
s2.course='python' #s2.__dict__['course']='python'
del s2.course #s2.__dict__.pop('course')
在程序中:先定義類,后產生對象

 !!!細說__init__方法!!!

#方式一、為對象初始化自己獨有的特征
class People:
    country='China'
    x=1
    def run(self):
        print('----->', self)

# 實例化出三個空對象
obj1=People()
obj2=People()
obj3=People()

# 為對象定制自己獨有的特征
obj1.name='egon'
obj1.age=18
obj1.sex='male'

obj2.name='lxx'
obj2.age=38
obj2.sex='female'

obj3.name='alex'
obj3.age=38
obj3.sex='female'

# print(obj1.__dict__)
# print(obj2.__dict__)
# print(obj3.__dict__)
# print(People.__dict__)





#方式二、為對象初始化自己獨有的特征
class People:
    country='China'
    x=1
    def run(self):
        print('----->', self)

# 實例化出三個空對象
obj1=People()
obj2=People()
obj3=People()

# 為對象定制自己獨有的特征
def chu_shi_hua(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male'
    obj.name = x
    obj.age = y
    obj.sex = z

chu_shi_hua(obj1,'egon',18,'male')
chu_shi_hua(obj2,'lxx',38,'female')
chu_shi_hua(obj3,'alex',38,'female')





#方式三、為對象初始化自己獨有的特征
class People:
    country='China'
    x=1

    def chu_shi_hua(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male'
        obj.name = x
        obj.age = y
        obj.sex = z

    def run(self):
        print('----->', self)


obj1=People()
# print(People.chu_shi_hua)
People.chu_shi_hua(obj1,'egon',18,'male')

obj2=People()
People.chu_shi_hua(obj2,'lxx',38,'female')

obj3=People()
People.chu_shi_hua(obj3,'alex',38,'female')




# 方式四、為對象初始化自己獨有的特征
class People:
    country='China'
    x=1

    def __init__(obj, x, y, z): #obj=obj1,x='egon',y=18,z='male'
        obj.name = x
        obj.age = y
        obj.sex = z

    def run(self):
        print('----->', self)

obj1=People('egon',18,'male') #People.__init__(obj1,'egon',18,'male')
obj2=People('lxx',38,'female') #People.__init__(obj2,'lxx',38,'female')
obj3=People('alex',38,'female') #People.__init__(obj3,'alex',38,'female')


# __init__方法
# 強調:
#   1、該方法內可以有任意的python代碼
#   2、一定不能有返回值
class People:
    country='China'
    x=1

    def __init__(obj, name, age, sex): #obj=obj1,x='egon',y=18,z='male'
        # if type(name) is not str:
        #     raise TypeError('名字必須是字符串類型')
        obj.name = name
        obj.age = age
        obj.sex = sex


    def run(self):
        print('----->', self)


# obj1=People('egon',18,'male')
obj1=People(3537,18,'male')

# print(obj1.run)
# obj1.run() #People.run(obj1)
# print(People.run)
!!!__init__方法之為對象定制自己獨有的特征

PS:

1. 站的角度不同,定義出的類是截然不同的,詳見面向對象實戰之需求分析

2. 現實中的類並不完全等於程序中的類,比如現實中的公司類,在程序中有時需要拆分成部門類,業務類...... 

3. 有時為了編程需求,程序中也可能會定義現實中不存在的類,比如策略類,現實中並不存在,但是在程序中卻是一個很常見的類

#python為類內置的特殊屬性
類名.__name__# 類的名字(字符串)
類名.__doc__# 類的文檔字符串
類名.__base__# 類的第一個父類(在講繼承時會講)
類名.__bases__# 類所有父類構成的元組(在講繼承時會講)
類名.__dict__# 類的字典屬性
類名.__module__# 類定義所在的模塊
類名.__class__# 實例對應的類(僅新式類中)
類的特殊屬性(了解即可)

!!!補充說明:從代碼級別看面向對象 !!!

#1、在沒有學習類這個概念時,數據與功能是分離的
def exc1(host,port,db,charset):
    conn=connect(host,port,db,charset)
    conn.execute(sql)
    return xxx


def exc2(host,port,db,charset,proc_name)
    conn=connect(host,port,db,charset)
    conn.call_proc(sql)
    return xxx

#每次調用都需要重復傳入一堆參數
exc1('127.0.0.1',3306,'db1','utf8','select * from tb1;')
exc2('127.0.0.1',3306,'db1','utf8','存儲過程的名字')




#2、我們能想到的解決方法是,把這些變量都定義成全局變量
HOST=‘127.0.0.1’
PORT=3306
DB=‘db1’
CHARSET=‘utf8’

def exc1(host,port,db,charset):
    conn=connect(host,port,db,charset)
    conn.execute(sql)
    return xxx


def exc2(host,port,db,charset,proc_name)
    conn=connect(host,port,db,charset)
    conn.call_proc(sql)
    return xxx

exc1(HOST,PORT,DB,CHARSET,'select * from tb1;')
exc2(HOST,PORT,DB,CHARSET,'存儲過程的名字')


#3、但是2的解決方法也是有問題的,按照2的思路,我們將會定義一大堆全局變量,這些全局變量並沒有做任何區分,即能夠被所有功能使用,然而事實上只有HOST,PORT,DB,CHARSET是給exc1和exc2這兩個功能用的。言外之意:我們必須找出一種能夠將數據與操作數據的方法組合到一起的解決方法,這就是我們說的類了

class MySQLHandler:
    def __init__(self,host,port,db,charset='utf8'):
        self.host=host
        self.port=port
        self.db=db
        self.charset=charset
    def exc1(self,sql):
        conn=connect(self.host,self.port,self.db,self.charset)
        res=conn.execute(sql)
        return res


    def exc2(self,sql):
        conn=connect(self.host,self.port,self.db,self.charset)
        res=conn.call_proc(sql)
        return res


obj=MySQLHandler('127.0.0.1',3306,'db1')
obj.exc1('select * from tb1;')
obj.exc2('存儲過程的名字')


#改進
class MySQLHandler:
    def __init__(self,host,port,db,charset='utf8'):
        self.host=host
        self.port=port
        self.db=db
        self.charset=charset
        self.conn=connect(self.host,self.port,self.db,self.charset)
    def exc1(self,sql):
        return self.conn.execute(sql)

    def exc2(self,sql):
        return self.conn.call_proc(sql)


obj=MySQLHandler('127.0.0.1',3306,'db1')
obj.exc1('select * from tb1;')
obj.exc2('存儲過程的名字')
數據與專門操作該數據的功能組合到一起

四 屬性查找

類有兩種屬性:數據屬性和函數屬性

1. 類的數據屬性是所有對象共享的

2. 類的函數屬性是綁定給對象用的

#類的數據屬性是所有對象共享的,id都一樣
print(id(OldboyStudent.school))

print(id(s1.school))
print(id(s2.school))
print(id(s3.school))

'''
4377347328
4377347328
4377347328
4377347328
'''



#類的函數屬性是綁定給對象使用的,obj.method稱為綁定方法,內存地址都不一樣
#ps:id是python的實現機制,並不能真實反映內存地址,如果有內存地址,還是以內存地址為准
print(OldboyStudent.learn)
print(s1.learn)
print(s2.learn)
print(s3.learn)
'''
<function OldboyStudent.learn at 0x1021329d8>
<bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x1021466d8>>
<bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146710>>
<bound method OldboyStudent.learn of <__main__.OldboyStudent object at 0x102146748>>
'''
View Code

在obj.name會先從obj自己的名稱空間里找name,找不到則去類中找,類也找不到就找父類...最后都找不到就拋出異常  

練習:編寫一個學生類,產生一堆學生對象,要求有一個計數器(屬性),統計總共實例了多少個對象 

五 綁定到對象的方法的特殊之處

#改寫
class OldboyStudent:
    school='oldboy'
    def __init__(self,name,age,sex):
        self.name=name
        self.age=age
        self.sex=sex
    def learn(self):
        print('%s is learning' %self.name) #新增self.name

    def eat(self):
        print('%s is eating' %self.name)

    def sleep(self):
        print('%s is sleeping' %self.name)


s1=OldboyStudent('李坦克','',18)
s2=OldboyStudent('王大炮','',38)
s3=OldboyStudent('牛榴彈','',78)

 

類中定義的函數(沒有被任何裝飾器裝飾的)是類的函數屬性,類可以使用,但必須遵循函數的參數規則,有幾個參數需要傳幾個參數

OldboyStudent.learn(s1) #李坦克 is learning
OldboyStudent.learn(s2) #王大炮 is learning
OldboyStudent.learn(s3) #牛榴彈 is learning

類中定義的函數(沒有被任何裝飾器裝飾的),其實主要是給對象使用的,而且是綁定到對象的,雖然所有對象指向的都是相同的功能,但是綁定到不同的對象就是不同的綁定方法

強調:綁定到對象的方法的特殊之處在於,綁定給誰就由誰來調用,誰來調用,就會將‘誰’本身當做第一個參數傳給方法,即自動傳值(方法__init__也是一樣的道理)

s1.learn() #等同於OldboyStudent.learn(s1)
s2.learn() #等同於OldboyStudent.learn(s2)
s3.learn() #等同於OldboyStudent.learn(s3)

注意:綁定到對象的方法的這種自動傳值的特征,決定了在類中定義的函數都要默認寫一個參數self,self可以是任意名字,但是約定俗成地寫出self。

 

類即類型

  提示:python的class術語與c++有一定區別,與 Modula-3更像。

  python中一切皆為對象,且python3中類與類型是一個概念,類型就是類

#類型dict就是類dict
>>> list
<class 'list'>

#實例化的到3個對象l1,l2,l3
>>> l1=list()
>>> l2=list()
>>> l3=list()

#三個對象都有綁定方法append,是相同的功能,但內存地址不同
>>> l1.append
<built-in method append of list object at 0x10b482b48>
>>> l2.append
<built-in method append of list object at 0x10b482b88>
>>> l3.append
<built-in method append of list object at 0x10b482bc8>

#操作綁定方法l1.append(3),就是在往l1添加3,絕對不會將3添加到l2或l3
>>> l1.append(3)
>>> l1
[3]
>>> l2
[]
>>> l3
[]
#調用類list.append(l3,111)等同於l3.append(111)
>>> list.append(l3,111) #l3.append(111)
>>> l3
[111] 

六 對象之間的交互

class Garen:        #定義英雄蓋倫的類,不同的玩家可以用它實例出自己英雄;
    camp='Demacia'  #所有玩家的英雄(蓋倫)的陣營都是Demacia;
    def __init__(self,nickname,aggressivity=58,life_value=455): #英雄的初始攻擊力58...;
        self.nickname=nickname  #為自己的蓋倫起個別名;
        self.aggressivity=aggressivity #英雄都有自己的攻擊力;
        self.life_value=life_value #英雄都有自己的生命值;
    def attack(self,enemy):   #普通攻擊技能,enemy是敵人;
        enemy.life_value-=self.aggressivity #根據自己的攻擊力,攻擊敵人就減掉敵人的生命值。

我們可以仿照garen類再創建一個Riven類

class Riven:
    camp='Noxus'  #所有玩家的英雄(銳雯)的陣營都是Noxus;
    def __init__(self,nickname,aggressivity=54,life_value=414): #英雄的初始攻擊力54;
        self.nickname=nickname  #為自己的銳雯起個別名;
        self.aggressivity=aggressivity #英雄都有自己的攻擊力;
        self.life_value=life_value #英雄都有自己的生命值;
    def attack(self,enemy):   #普通攻擊技能,enemy是敵人;
        enemy.life_value-=self.aggressivity #根據自己的攻擊力,攻擊敵人就減掉敵人的生命值。 

實例出倆英雄

>>> g1=Garen('草叢倫')
>>> r1=Riven('銳雯雯')

交互:銳雯雯攻擊草叢倫,反之一樣

>>> g1.life_value
455
>>> r1.attack(g1)
>>> g1.life_value
401 

補充:

  garen_hero.Q()稱為向garen_hero這個對象發送了一條消息,讓他去執行Q這個功能,類似的有:

  garen_hero.W()

  garen_hero.E()

  garen_hero.R()

七 練習

鏈接:http://www.cnblogs.com/linhaifeng/articles/7340497.html

八 繼承與派生

鏈接:http://www.cnblogs.com/linhaifeng/articles/7340153.html

九 多態與多態性

鏈接:http://www.cnblogs.com/linhaifeng/articles/7340687.html

十 封裝

鏈接:http://www.cnblogs.com/linhaifeng/articles/7340801.html

十二 小白容易犯的錯誤

1.面向對象的程序設計看起來高大上,所以我在編程時就應該保證通篇class,這樣寫出的程序一定是好的程序(面向對象只適合那些可擴展性要求比較高的場景)

2.很多人喜歡說面向對象三大特性(這是從哪傳出來的,封裝,多態,繼承?漏洞太多太多,好吧暫且稱為三大特性),那么我在基於面向對象編程時,我一定要讓我定義的類中完整的包含這三種特性,這樣寫肯定是好的程序

好家伙,我說降龍十八掌有十八掌,那么你每次跟人干仗都要從第一掌打到第18掌這才顯得你會了是么:面對敵人,你打到第三掌對方就已經倒下了,你說,不行,你給老子起來,老子還沒有show完...

3.類有類屬性,實例有實例屬性,所以我們在定義class時一定要定義出那么幾個類屬性,想不到怎么辦,那就使勁的想,定義的越多越牛逼

這就犯了一個嚴重的錯誤,程序越早面向對象,死的越早,為啥面向對象,因為我們要將數據與功能結合到一起,程序整體的結構都沒有出來,或者說需要考慮的問題你都沒有搞清楚個八九不離十,你就開始面向對象了,這就導致了,你在那里干想,自以為想通了,定義了一堆屬性,結果后來又都用不到,或者想不通到底應該定義啥,那就一直想吧,想着想着就瘋了。

你見過哪家公司要開發一個軟件,上來就開始寫,肯定是頻繁的開會討論計划,請看第八節

4.既然這么麻煩,那么我徹底解脫了,我們不要用面向對象編程了,你啊,你有大才,你能成事啊,傻叉。

十三 python中關於OOP的常用術語

抽象/實現

抽象指對現實世界問題和實體的本質表現,行為和特征建模,建立一個相關的子集,可以用於 繪程序結構,從而實現這種模型。抽象不僅包括這種模型的數據屬性,還定義了這些數據的接口。

對某種抽象的實現就是對此數據及與之相關接口的現實化(realization)。現實化這個過程對於客戶 程序應當是透明而且無關的。 

封裝/接口

封裝描述了對數據/信息進行隱藏的觀念,它對數據屬性提供接口和訪問函數。通過任何客戶端直接對數據的訪問,無視接口,與封裝性都是背道而馳的,除非程序員允許這些操作。作為實現的 一部分,客戶端根本就不需要知道在封裝之后,數據屬性是如何組織的。在Python中,所有的類屬性都是公開的,但名字可能被“混淆”了,以阻止未經授權的訪問,但僅此而已,再沒有其他預防措施了。這就需要在設計時,對數據提供相應的接口,以免客戶程序通過不規范的操作來存取封裝的數據屬性。

注意:封裝絕不是等於“把不想讓別人看到、以后可能修改的東西用private隱藏起來”

真正的封裝是,經過深入的思考,做出良好的抽象,給出“完整且最小”的接口,並使得內部細節可以對外透明

(注意:對外透明的意思是外部調用者可以順利的得到自己想要的任何功能,完全意識不到內部細節的存在)

合成

合成擴充了對類的 述,使得多個不同的類合成為一個大的類,來解決現實問題。合成 述了 一個異常復雜的系統,比如一個類由其它類組成,更小的組件也可能是其它的類,數據屬性及行為, 所有這些合在一起,彼此是“有一個”的關系。

派生/繼承/繼承結構

派生描述了子類衍生出新的特性,新類保留已存類類型中所有需要的數據和行為,但允許修改或者其它的自定義操作,都不會修改原類的定義。
繼承描述了子類屬性從祖先類繼承這樣一種方式
繼承結構表示多“代”派生,可以述成一個“族譜”,連續的子類,與祖先類都有關系。

泛化/特化

基於繼承
泛化表示所有子類與其父類及祖先類有一樣的特點。
特化描述所有子類的自定義,也就是,什么屬性讓它與其祖先類不同。

多態與多態性

多態指的是同一種事物的多種狀態:水這種事物有多種不同的狀態:冰,水蒸氣

多態性的概念指出了對象如何通過他們共同的屬性和動作來操作及訪問,而不需考慮他們具體的類。

冰,水蒸氣,都繼承於水,它們都有一個同名的方法就是變成雲,但是冰.變雲(),與水蒸氣.變雲()是截然不同的過程,雖然調用的方法都一樣

自省/反射

自省也稱作反射,這個性質展示了某對象是如何在運行期取得自身信息的。如果傳一個對象給你,你可以查出它有什么能力,這是一項強大的特性。如果Python不支持某種形式的自省功能,dir和type內建函數,將很難正常工作。還有那些特殊屬性,像__dict__,__name__及__doc__

 

十四 面向對象的軟件開發

    很多人在學完了python的class機制之后,遇到一個生產中的問題,還是會懵逼,這其實太正常了,因為任何程序的開發都是先設計后編程,python的class機制只不過是一種編程方式,如果你硬要拿着class去和你的問題死磕,變得更加懵逼都是分分鍾的事,在以前,軟件的開發相對簡單,從任務的分析到編寫程序,再到程序的調試,可以由一個人或一個小組去完成。但是隨着軟件規模的迅速增大,軟件任意面臨的問題十分復雜,需要考慮的因素太多,在一個軟件中所產生的錯誤和隱藏的錯誤、未知的錯誤可能達到驚人的程度,這也不是在設計階段就完全解決的。

    所以軟件的開發其實一整套規范,我們所學的只是其中的一小部分,一個完整的開發過程,需要明確每個階段的任務,在保證一個階段正確的前提下再進行下一個階段的工作,稱之為軟件工程

    面向對象的軟件工程包括下面幾個部:

1.面向對象分析(object oriented analysis ,OOA)

    軟件工程中的系統分析階段,要求分析員和用戶結合在一起,對用戶的需求做出精確的分析和明確的表述,從大的方面解析軟件系統應該做什么,而不是怎么去做。面向對象的分析要按照面向對象的概念和方法,在對任務的分析中,從客觀存在的事物和事物之間的關系,貴南出有關的對象(對象的‘特征’和‘技能’)以及對象之間的聯系,並將具有相同屬性和行為的對象用一個類class來標識。

    建立一個能反映這是工作情況的需求模型,此時的模型是粗略的。

2 面向對象設計(object oriented design,OOD)

    根據面向對象分析階段形成的需求模型,對每一部分分別進行具體的設計。

    首先是類的設計,類的設計可能包含多個層次(利用繼承與派生機制)。然后以這些類為基礎提出程序設計的思路和方法,包括對算法的設計。

    在設計階段並不牽涉任何一門具體的計算機語言,而是用一種更通用的描述工具(如偽代碼或流程圖)來描述

3 面向對象編程(object oriented programming,OOP)

    根據面向對象設計的結果,選擇一種計算機語言把它寫成程序,可以是python

4 面向對象測試(object oriented test,OOT)

    在寫好程序后交給用戶使用前,必須對程序進行嚴格的測試,測試的目的是發現程序中的錯誤並修正它。

    面向對的測試是用面向對象的方法進行測試,以類作為測試的基本單元。

5 面向對象維護(object oriendted soft maintenance,OOSM)

    正如對任何產品都需要進行售后服務和維護一樣,軟件在使用時也會出現一些問題,或者軟件商想改進軟件的性能,這就需要修改程序。

    由於使用了面向對象的方法開發程序,使用程序的維護比較容易。

    因為對象的封裝性,修改一個對象對其他的對象影響很小,利用面向對象的方法維護程序,大大提高了軟件維護的效率,可擴展性高。

 

    在面向對象方法中,最早發展的肯定是面向對象編程(OOP),那時OOA和OOD都還沒有發展起來,因此程序設計者為了寫出面向對象的程序,還必須深入到分析和設計領域,尤其是設計領域,那時的OOP實際上包含了現在的OOD和OOP兩個階段,這對程序設計者要求比較高,許多人感到很難掌握。

    現在設計一個大的軟件,是嚴格按照面向對象軟件工程的5個階段進行的,這個5個階段的工作不是由一個人從頭到尾完成的,而是由不同的人分別完成,這樣OOP階段的任務就比較簡單了。程序編寫者只需要根據OOd提出的思路,用面向對象語言編寫出程序既可。

十五 面向對象實戰

鏈接:http://www.cnblogs.com/linhaifeng/articles/7341318.html

 

本周作業

角色:學校、學員、課程、講師
要求:
1. 創建北京、上海 2 所學校
2. 創建linux , python , go 3個課程 , linux\py 在北京開, go 在上海開
3. 課程包含,周期,價格,通過學校創建課程 
4. 通過學校創建班級, 班級關聯課程、講師
5. 創建學員時,選擇學校,關聯班級
5. 創建講師角色時要關聯學校, 
6. 提供兩個角色接口
6.1 學員視圖, 可以注冊, 交學費, 選擇班級,
6.2 講師視圖, 講師可管理自己的班級, 上課時選擇班級, 查看班級學員列表 , 修改所管理的學員的成績 
6.3 管理視圖,創建講師, 創建班級,創建課程

7. 上面的操作產生的數據都通過pickle序列化保存到文件里

 

 

 

 

 

 

 

 



 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM