Day6 - Python基础6 面向对象编程 --转自金角大王

本节内容:
 
面向对象编程介绍
为何要用面向对象进行开发?
面向对象的特性:封装、继承、多态
类、方法、
 
 

引子

你如今是一家游戏公司的开发人员,如今须要你开发一款叫作<人狗大战>的游戏,你就思考呀,人狗做战,那至少须要2个角色,一个是人, 一个是狗,且人和狗都有不一样的技能,好比人拿棍打狗, 狗能够咬人,怎么描述这种不一样的角色和他们的功能呢?
 
你搜罗了本身掌握的全部技能,写出了下面的代码来描述这两个角色

上面两个方法至关于造了两个模子,游戏开始,你得生成一我的和狗的实际对象吧,怎么生成呢?html

 

两个角色对象生成了,狗和人还有不一样的功能呀,狗会咬人,人会打狗,对不对? 怎么实现呢,。。想到了, 能够每一个功能再写一个函数,想执行哪一个功能,直接 调用 就能够了,对不?python

上面的功能实现的简直是完美!linux

可是仔细玩耍一会,你就不当心干了下面这件事程序员

事实 上,这并没出错。很显然,人是不能调用狗的功能的,如何在代码级别实现这个限制呢?算法

你是如此的机智,这样就实现了限制人只能用人本身的功能啦。数据库

但,个人哥,不要高兴太早,刚才你只是阻止了两个彻底 不一样的角色 以前的功能混用, 但有没有可能 ,同一个种角色,但有些属性是不一样的呢? 好比 ,你们都打过cs吧,cs里有警察和恐怖份子,但由于都 是人, 因此你写一个角色叫 person(), 警察和恐怖份子都 能够 互相射击,但警察不能够杀人质,恐怖分子能够,这怎么实现呢? 你想了说想,说,简单,只须要在杀人质的功能里加个判断,若是是警察,就不让杀不就ok了么。 没错, 这虽然 解决了杀人质的问题,但其实你会发现,警察和恐怖分子的区别还有不少,同时又有不少共性,若是 在每一个区别处都 单独作判断,那得累死。 编程

你想了想说, 那就直接写2个角色吧, 反正 这么多区别, 个人哥, 不能写两个角色呀,由于他们还有不少共性 , 写两个不一样的角色,就表明 相同的功能 也要重写了,是否是个人哥? 。。。数据结构

好了, 话题就给你点到这, 再多说你的智商 也理解不了了!运维

 

 

  

 

  

面向过程 VS 面向对象 

编程范式

编程是 程序 员 用特定的语法+数据结构+算法组成的代码来告诉计算机如何执行任务的过程 , 一个程序是程序员为了获得一个任务结果而编写的一组指令的集合,正所谓条条大路通罗马,实现一个任务的方式有不少种不一样的方式, 对这些不一样的编程方式的特色进行概括总结得出来的编程方式类别,即为编程范式。 不一样的编程范式本质上表明对各类类型的任务采起的不一样的解决问题的思路, 大多数语言只支持一种编程范式,固然也有些语言能够同时支持多种编程范式。 两种最重要的编程范式分别是面向过程编程和面向对象编程。编程语言

面向过程编程(Procedural Programming)
Procedural programming uses a list of instructions to tell the computer what to do step-by-step.
面向过程编程依赖 - 你猜到了- procedures,一个procedure包含一组要被进行计算的步骤, 面向过程又被称为top-down languages, 就是程序从上到下一步步执行,一步步从上到下,从头至尾的解决问题 。基本设计思路就是程序一开始是要着手解决一个大的问题,而后把一个大问题分解成不少个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到能够在一个小步骤范围内解决。

举个典型的面向过程的例子, 数据库备份, 分三步,链接数据库,备份数据库,测试备份文件可用性。

代码以下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def db_conn():
     print ( "connecting db..." )
 
 
def db_backup(dbname):
     print ( "导出数据库..." ,dbname)
     print ( "将备份文件打包,移至相应目录..." )
 
def db_backup_test():
     print ( "将备份文件导入测试库,看导入是否成功" )
 
 
def main():
     db_conn()
     db_backup( 'my_db' )
     db_backup_test()
 
 
 
if __name__ = = '__main__' :
     main()

  

这样作的问题也是显而易见的,就是若是你要对程序进行修改,对你修改的那部分有依赖的各个部分你都也要跟着修改, 举个例子,若是程序开头你设置了一个变量值 为1 , 但若是其它子过程依赖这个值 为1的变量才能正常运行,那若是你改了这个变量,那这个子过程你也要修改,假如又有一个其它子程序依赖这个子过程 , 那就会发生一连串的影响,随着程序愈来愈大, 这种编程方式的维护难度会愈来愈高。
因此咱们通常认为, 若是你只是写一些简单的脚本,去作一些一次性任务,用面向过程的方式是极好的,但若是你要处理的任务是复杂的,且须要不断迭代和维护 的, 那仍是用面向对象最方便了。

 
 

面向对象编程

OOP编程是利用“类”和“对象”来建立各类模型来实现对真实世界的描述,使用面向对象编程的缘由一方面是由于它可使程序的维护和扩展变得更简单,而且能够大大提升程序开发效率 ,另外,基于面向对象的程序可使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。

面向对象的几个核心特性以下

Class 类
一个类便是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具有的属性(variables(data))、共同的方法

Object 对象
一个对象便是一个类的实例化后实例,一个类必须通过实例化后方可在程序中调用,一个类能够实例化多个对象,每一个对象亦能够有不一样的属性,就像人类是指全部人,每一个人是指具体的对象,人与人以前有共性,亦有不一样

Encapsulation 封装
在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法

Inheritance 继承
一个类能够派生出子类,在这个父类里定义的属性、方法自动被子类继承

Polymorphism 多态
多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不一样的子类,且每一个子类在继承了一样的方法名的同时又对父类的方法作了不一样的实现,这就是同一种事物表现出的多种形态。
编程其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再经过这个抽象的事物, 与不一样的具体事物进行对话。
对不一样类的对象发出相同的消息将会有不一样的行为。好比,你的老板让全部员工在九点钟开始工做, 他只要在九点钟的时候说:“开始工做”便可,而不须要对销售人员说:“开始销售工做”,对技术人员说:“开始技术工做”, 由于“员工”是一个抽象的事物, 只要是员工就能够开始工做,他知道这一点就好了。至于每一个员工,固然会各司其职,作各自的工做。
多态容许将子类的对象看成父类的对象使用,某父类型的引用指向其子类型的对象,调用的方法是该子类型的方法。这里引用和调用方法的代码编译前就已经决定了,而引用所指向的对象能够在运行期间动态绑定

 

面向对象编程(Object-Oriented Programming )介绍

 
对于编程语言的初学者来说,OOP不是一个很容易理解的编程方式,你们虽然都按老师讲的都知道OOP的三大特性是继承、封装、多态,而且你们也都知道了如何定义类、方法等面向对象的经常使用语法,可是一到真正写程序的时候,仍是不少人喜欢用函数式编程来写代码,特别是初学者,很容易陷入一个窘境就是“我知道面向对象,我也会写类,但我依然没发如今使用了面向对象后,对咱们的程序开发效率或其它方面带来什么好处,由于我使用函数编程就能够减小重复代码并作到程序可扩展了,为啥子还用面向对象?”。 对于此,我我的以为缘由应该仍是由于你没有充分了解到面向对象能带来的好处,今天我就写一篇关于面向对象的入门文章,但愿能帮你们更好的理解和使用面向对象编程。  
 
不管用什么形式来编程,咱们都要明确记住如下原则:
  1. 写重复代码是很是很差的低级行为
  2. 你写的代码须要常常变动 
 
开发正规的程序跟那种写个运行一次就扔了的小脚本一个很大不一样就是,你的代码老是须要不断的更改,不是修改bug就是添加新功能等,因此为了往后方便程序的修改及扩展,你写的代码必定要遵循易读、易改的原则(专业数据叫可读性好、易扩展)。
 
若是你把一段一样的代码复制、粘贴到了程序的多个地方以实如今程序的各个地方调用 这个功能,那往后你再对这个功能进行修改时,就须要把程序里多个地方都改一遍,这种写程序的方式是有问题的,由于若是你不当心漏掉了一个地方没改,那可能会致使整个程序的运行都 出问题。 所以咱们知道 在开发中必定要努力避免写重复的代码,不然就至关于给本身再挖坑。
 
还好,函数的出现就能帮咱们轻松的解决重复代码的问题,对于须要重复调用的功能,只须要把它写成一个函数,而后在程序的各个地方直接调用这个函数名就行了,而且当须要修改这个功能时,只需改函数代码,而后整个程序就都更新了。
 
其实OOP编程的主要做用也是使你的代码修改和扩展变的更容易,那么小白要问了,既然函数都能实现这个需求了,还要OOP干毛线用呢? 呵呵,说这话就像,古时候,人们打仗杀人都用刀,后来出来了枪,它的主要功能跟刀同样,也是杀人,而后小白就问,既然刀能杀人了,那还要枪干毛线,哈哈,显而易见,由于枪能更好更快更容易的杀人。函数编程与OOP的主要区别就是OOP可使程序更加容易扩展和易更改。
 
小白说,我读书少,你别骗我,口说无凭,证实一下,好吧,那咱们就下面的例子证实给小白看。 
相信你们都打过CS游戏吧,咱们就本身开发一个简单版的CS来玩一玩。 
 
 
 
暂不考虑开发场地等复杂的东西,咱们先从人物角色下手, 角色很简单,就俩个,恐怖份子、警察,他们除了角色不一样,其它基本都 同样,每一个人都有生命值、武器等。 我们先用非OOP的方式写出游戏的基本角色 
?
1
2
3
4
5
6
7
8
9
10
11
#role 1
name = 'Alex'
role = 'terrorist'
weapon = 'AK47'
life_value = 100
 
#rolw 2
name2 = 'Jack'
role2 = 'police'
weapon2 = 'B22'
life_value2 = 100

 

上面定义了一个恐怖份子Alex和一个警察Jack,但只2我的很差玩呀,一干就死了,没意思,那咱们再分别一个恐怖分子和警察吧,
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#role 1
name = 'Alex'
role = 'terrorist'
weapon = 'AK47'
life_value = 100
money = 10000
 
#rolw 2
name2 = 'Jack'
role2 = 'police'
weapon2 = 'B22'
life_value2 = 100
money2 = 10000
 
#role 3
name3 = 'Rain'
role3 = 'terrorist'
weapon3 = 'C33'
life_value3 = 100
money3 = 10000
 
#rolw 4
name4 = 'Eric'
role4 = 'police'
weapon4 = 'B51'
life_value4 = 100
money4 = 10000

 

4个角色虽然建立好了,可是有个问题就是,每建立一个角色,我都要单独命名,name1,name2,name3,name4…,后面的调用的时候这个变量名你还都得记着,要是再让多加几个角色,估计调用时就很容易弄混啦,因此咱们想想,可否全部的角色的变量名都是同样的,但调用的时候又能区分开分别是谁? 
 
固然能够,咱们只须要把上面的变量改为字典的格式就能够啦。 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
roles = {
     1 :{ 'name' : 'Alex' ,
        'role' : 'terrorist' ,
        'weapon' : 'AK47' ,
        'life_value' : 100 ,
        'money' : 15000 ,
        },
     2 :{ 'name' : 'Jack' ,
        'role' : 'police' ,
        'weapon' : 'B22' ,
        'life_value' : 100 ,
         'money' : 15000 ,
        },
     3 :{ 'name' : 'Rain' ,
        'role' : 'terrorist' ,
        'weapon' : 'C33' ,
        'life_value' : 100 ,
        'money' : 15000 ,
        },
     4 :{ 'name' : 'Eirc' ,
        'role' : 'police' ,
        'weapon' : 'B51' ,
        'life_value' : 100 ,
        'money' : 15000 ,
        },
}
 
print (roles[ 1 ]) #Alex
print (roles[ 2 ]) #Jack

 

很好,这个之后调用这些角色时只须要roles[1],roles[2]就能够啦,角色的基本属性设计完了后,咱们接下来为每一个角色开发如下几个功能
  1. 被打中后就会掉血的功能
  2. 开枪功能
  3. 换子弹
  4. 买枪
  5. 跑、走、跳、下蹲等动做
  6. 保护人质(仅适用于警察)
  7. 不能杀同伴
  8. 。。。
咱们能够把每一个功能写成一个函数,相似以下: 
?
1
2
3
4
5
6
7
8
9
10
11
def shot(by_who):
     #开了枪后要减子弹数
     pass
def got_shot(who):
     #中枪后要减血
     who[‘life_value’] - = 10
     pass
def buy_gun(who,gun_name):
     #检查钱够不够,买了枪后要扣钱
     pass
...

 

so far so good, 继续按照这个思路设计,再完善一下代码,游戏的简单版就出来了,可是在往下走以前,咱们来看看上面的这种代码写法有没有问题,至少从上面的代码设计中,我看到如下几点缺陷:
  1. 每一个角色定义的属性名称是同样的,但这种命名规则是咱们本身约定的,从程序上来说,并无进行属性合法性检测,也就是说role 1定义的表明武器的属性是weapon, role 2 ,3,4也是同样的,不过若是我在新增一个角色时不当心把weapon 写成了wepon , 这个程序自己是检测 不到的
  2. terrorist 和police这2个角色有些功能是不一样的,好比police是不能杀人质的,可是terrorist可能,随着这个游戏开发的更复杂,咱们会发现这2个角色后续有更多的不一样之处, 但如今的这种写法,咱们是没办法 把这2个角色适用的功能区分开来的,也就是说,每一个角色均可以直接调用任意功能,没有任何限制。
  3. 咱们在上面定义了got_shot()后要减血,也就是说减血这个动做是应该经过被击中这个事件来引发的,咱们调用get_shot(),got_shot()这个函数再调用每一个角色里的life_value变量来减血。 但其实我不经过got_shot(),直接调用角色roles[role_id][‘life_value’] 减血也能够呀,可是若是这样调用的话,那能够就是简单粗暴啦,由于减血以前其它还应该判断此角色是否穿了防弹衣等,若是穿了的话,伤害值确定要减小,got_shot()函数里就作了这样的检测,你这里直接绕过的话,程序就乱了。 所以这里应该设计 成除了经过got_shot(),其它的方式是没有办法给角色减血的,不过在上面的程序设计里,是没有办法实现的。 
  4. 如今须要给全部角色添加一个能够穿防弹衣的功能,那很显然你得在每一个角色里放一个属性来存储此角色是否穿 了防弹衣,那就要更改每一个角色的代码,给添加一个新属性,这样太low了,不符合代码可复用的原则
 
 
上面这4点问题若是不解决,之后确定会引出更大的坑,有同窗说了,解决也不复杂呀,直接在每一个功能调用时作一下角色判断啥就行了,没错,你要非得这么霸王硬上弓的搞也确定是能够实现的,那你本身就开发相应的代码来对上面提到的问题进行处理好啦。 但这些问题其实能过OOP就能够很简单的解决。 
 
以前的代码改为用OOP中的“类”来实现的话以下: 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Role( object ):
     def __init__( self ,name,role,weapon,life_value = 100 ,money = 15000 ):
         self .name = name
         self .role = role
         self .weapon = weapon
         self .life_value = life_value
         self .money = money
 
     def shot( self ):
         print ( "shooting..." )
 
     def got_shot( self ):
         print ( "ah...,I got shot..." )
 
     def buy_gun( self ,gun_name):
         print ( "just bought %s" % gun_name)
 
r1 = Role( 'Alex' , 'police' ,'AK47’) #生成一个角色
r2 = Role( 'Jack' , 'terrorist' ,'B22’)  #生成一个角色

 

先不考虑语法细节,相比靠函数拼凑出来的写法,上面用面向对象中的类来写最直接的改进有如下2点:
  1. 代码量少了近一半
  2. 角色和它所具备的功能能够一目了然看出来
 

在真正开始分解上面代码含义之以前,咱们现来了解一些类的基本定义
类的语法
?
1
2
3
4
5
6
7
8
9
class Dog( object ):
 
     print ( "hello,I am a dog!" )
 
 
d = Dog() #实例化这个类,
#此时的d就是类Dog的实例化对象
 
#实例化,其实就是以Dog类为模版,在内存里开辟一块空间,存上数据,赋值成一个变量名

上面的代码其实有问题,想给狗起名字传不进去。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
class Dog( object ):
 
     def __init__( self ,name,dog_type):
         self .name = name
         self . type = dog_type
 
     def sayhi( self ):
 
         print ( "hello,I am a dog, my name is " , self .name)
 
 
d = Dog( 'LiChuang' , "京巴" )
d.sayhi()

为何有__init__? 为何有self? 此时的你一脸蒙逼,相信不画个图,你的智商是理解不了的!  

画图以前, 你先注释掉这两句

?
1
2
3
4
# d = Dog('LiChuang', "京巴")
# d.sayhi()
 
print (Dog)

没实例直接打印Dog输出以下

?
1
< class '__main__.Dog' >

这表明什么?表明 即便不实例化,这个Dog类自己也是已经存在内存里的对不对, yes, cool,那实例化时,会产生什么化学反应呢?

 根据上图咱们得知,其实self,就是实例自己!你实例化时python会自动把这个实例自己经过self参数传进去。

你说好吧,伪装懂了, 但下面这段代码你又不明白了, 为什么sayhi(self),要写个self呢? 

?
1
2
3
4
5
class Dog( object ):
     ...
     def sayhi( self ):
 
         print ( "hello,I am a dog, my name is " , self .name)

这个缘由,我课上在讲。。。    

?
1
<br><br><br><br>
 

 
好了,明白 了类的基本定义,接下来咱们一块儿分解一下上面的代码分别 是什么意思 
?
1
2
3
4
5
6
7
class Role( object ): #定义一个类, class是定义类的语法,Role是类名,(object)是新式类的写法,必须这样写,之后再讲为何
     def __init__( self ,name,role,weapon,life_value = 100 ,money = 15000 ): #初始化函数,在生成一个角色时要初始化的一些属性就填写在这里
         self .name = name #__init__中的第一个参数self,和这里的self都 是什么意思? 看下面解释
         self .role = role
         self .weapon = weapon
         self .life_value = life_value
         self .money = money

 

上面的这个__init__()叫作初始化方法(或构造方法), 在类被调用时,这个方法(虽然它是函数形式,但在类中就不叫函数了,叫方法)会自动执行,进行一些初始化的动做,因此咱们这里写的__init__(self,name,role,weapon,life_value=100,money=15000)就是要在建立一个角色时给它设置这些属性,那么这第一个参数self是干毛用的呢? 
 
初始化一个角色,就须要调用这个类一次: 
?
1
2
r1 = Role( 'Alex' , 'police' ,'AK47’) #生成一个角色 , 会自动把参数传给Role下面的__init__(...)方法
r2 = Role( 'Jack' , 'terrorist' ,'B22’)  #生成一个角色

咱们看到,上面的建立角色时,咱们并无给__init__传值,程序也没未报错,是由于,类在调用它本身的__init__(…)时本身帮你给self参数赋值了, 

?
1
2
r1 = Role( 'Alex' , 'police' , 'AK47’) #此时self 至关于 r1 ,  Role(r1,' Alex ',' police ',' AK47’)
r2 = Role( 'Jack' , 'terrorist' , 'B22’)#此时self 至关于 r2, Role(r2,' Jack ',' terrorist ',' B22’)

 

为何这样子?你拉着我说你有些犹豫,怎么会这样子?
你执行 r1 = Role('Alex','police','AK47)时,python的解释器其实干了两件事:
  1. 在内存中开辟一块空间指向r1这个变量名
  2. 调用Role这个类并执行其中的__init__(…)方法,至关于Role.__init__(r1,'Alex','police',AK47’),这么作是为何呢? 是为了把'Alex','police',’AK47’这3个值跟刚开辟的r1关联起来,是为了把'Alex','police',’AK47’这3个值跟刚开辟的r1关联起来,是为了把'Alex','police',’AK47’这3个值跟刚开辟的r1关联起来,重要的事情说3次, 由于关联起来后,你就能够直接r1.name, r1.weapon 这样来调用啦。因此,为实现这种关联,在调用__init__方法时,就必须把r1这个变量也传进去,不然__init__不知道要把那3个参数跟谁关联呀。
  3. 明白了么哥?因此这个__init__(…)方法里的,self.name = name , self.role = role 等等的意思就是要把这几个值 存到r1的内存空间里。
若是还不明白的话,哥,去测试一下智商吧, 应该不会超过70,哈哈。
为了暴露本身的智商,此时你伪装懂了,但又问, __init__(…)我懂了,但后面的那几个函数,噢 不对,后面那几个方法 为何也还须要self参数么? 不是在初始化角色的时候 ,就已经把角色的属性跟r1绑定好了么? 
good question, 先来看一下上面类中的一个buy_gun的方法: 
?
1
2
def buy_gun( self ,gun_name):
     print (“ % s has just bought % s” % ( self .name,gun_name) )

 

上面这个方法经过类调用的话要写成以下: 
 
?
1
2
r1 = Role( 'Alex' , 'police' , 'AK47' )
r1.buy_gun( "B21”) #python 会自动帮你转成 Role.buy_gun(r1,”B21" )

 

执行结果
#Alex has just bought B21 
依然没给self传值 ,但Python仍是会自动的帮你把r1 赋值给self这个参数, 为何呢? 由于,你在buy_gun(..)方法中可能要访问r1的一些其它属性呀, 好比这里就访问 了r1的名字,怎么访问呢?你得告诉这个方法呀,因而就把r1传给了这个self参数,而后在buy_gun里调用 self.name 就至关于调用r1.name 啦,若是还想知道r1的生命值 有多少,直接写成self.life_value就能够了。 说白了就是在调用类中的一个方法时,你得告诉人家你是谁。
 
好啦, 总结一下2点:
  1. 上面的这个r1 = Role('Alex','police','AK47)动做,叫作类的“实例化”, 就是把一个虚拟的抽象的类,经过这个动做,变成了一个具体的对象了, 这个对象就叫作实例
  2. 刚才定义的这个类体现了面向对象的第一个基本特性,封装,其实就是使用构造方法将内容封装到某个具体对象中,而后经过对象直接或者self间接获取被封装的内容
 

面向对象的特性:

封装

封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。

封装,也就是把客观事物封装成抽象的类,而且类能够把本身的数据和方法只让可信的类或者对象操做,对不可信的进行信息隐藏。

继承

面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可使用现有类的全部功能,并在无需从新编写原来的类的状况下对这些功能进行扩展。

经过继承建立的新类称为“子类”或“派生类”。

被继承的类称为“基类”、“父类”或“超类”。

继承的过程,就是从通常到特殊的过程。

要实现继承,能够经过“继承”(Inheritance)和“组合”(Composition)来实现。

在某些 OOP 语言中,一个子类能够继承多个基类。可是通常状况下,一个子类只能有一个基类,要实现多重继承,能够经过多级继承来实现。

继承概念的实现方式主要有2类:实现继承、接口继承。

Ø         实现继承是指使用基类的属性和方法而无需额外编码的能力;
Ø         接口继承是指仅使用属性和方法的名称、可是子类必须提供实现的能力(子类重构爹类方法);
在考虑使用继承时,有一点须要注意,那就是两个类之间的关系应该是“属于”关系。例如,Employee 是一我的,Manager 也是一我的,所以这两个类均可以继承 Person 类。可是 Leg 类却不能继承 Person 类,由于腿并非一我的。
 
抽象类仅定义将由子类建立的通常属性和方法。

OO开发范式大体为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。

继承示例

  

 

多态

 
多态性(polymorphisn)是容许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值以后,父对象就能够根据当前赋值给它的子对象的特性以不一样的方式运做。简单的说,就是一句话:容许将子类类型的指针赋值给父类类型的指针。
那么,多态的做用是什么呢?咱们知道,封装能够隐藏实现细节,使得代码模块化;继承能够扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另外一个目的——接口重用!多态的做用,就是为了类在继承和派生的时候,保证使用“家谱”中任一类的实例的某一属性时的正确调用。
 
Pyhon 不少语法都是支持多态的,好比 len(),sorted(), 你给len传字符串就返回字符串的长度,传列表就返回列表长度。
 
Python多态示例
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#_*_coding:utf-8_*_
 
 
class Animal( object ):
     def __init__( self , name):  # Constructor of the class
         self .name = name
 
     def talk( self ):              # Abstract method, defined by convention only
         raise NotImplementedError( "Subclass must implement abstract method" )
 
 
class Cat(Animal):
     def talk( self ):
         print ( '%s: 喵喵喵!' % self .name)
 
 
class Dog(Animal):
     def talk( self ):
         print ( '%s: 汪!汪!汪!' % self .name)
 
 
 
def func(obj): #一个接口,多种形态
     obj.talk()
 
c1 = Cat( '小晴' )
d1 = Dog( '李磊' )
 
func(c1)
func(d1)

  

 

领域模型 

好了,你如今会了面向对象的各类语法了, 那请看下本章最后的做业需求,我相信你多是蒙蔽的, 不少同窗都是学会了面向对象的语法,却依然写不出面向对象的程序,缘由是什么呢?缘由就是由于你还没掌握一门面向对象设计利器, 你说我读书少别骗我, 什么利器? 

答案就是:领域建模。 从领域模型开始,咱们就开始了面向对象的分析和设计过程,能够说,领域模型是完成从需求分析到面向 对象设计的一座桥梁。 

 

领域模型,顾名思义,就是需求所涉及的领域的一个建模,更通俗的讲法是业务模型。 参考百度百科(http://baike.baidu.cn/view/757895.htm ),领域模型定义以下: 

从这个定义咱们能够看出,领域模型有两个主要的做用:

  1. 发掘重要的业务领域概念
  2. 创建业务领域概念之间的关系 

 

 

领域建模三字经 

领域模型如此重要,不少同窗可能会认为领域建模很复杂,须要很高的技巧。然而事实上领域建模很是简 单,简单得有点难以让人相信,领域建模的方法归纳一下就是“找名词”! 许多同窗看到这个方法后估计都会笑出来:太假了吧,这么简单,找个初中生都会啊,那咱们公司那些分 析师和设计师还有什么用哦?

分析师和设计师固然有用,后面咱们会看到,即便是简单的找名词这样的操做,也涉及到分析和提炼,而 不是简单的摘取出来就可,这种状况下分析师和设计师的经验和技能就可以派上用场了。但领域模型分析 也确实相对简单,即便没有丰富的经验和高超的技巧,至少也能完成一个能用的领域模型。 

虽然咱们说“找名词”很简单,但一个关键的问题尚未说明:从哪里找? 若是你还记得领域模型是“需求到面向对象的桥梁”,那么你确定一会儿就能想到:从需求模型中找,具 体来讲就是从用例中找。 

 

概括一下域建模的方法就是“从用例中找名词”。 固然,找到名词后,为了可以更加符合面向对象的要求和特色,咱们还须要对这些名词进一步完善,这就 是接下来的步骤:加属性,连关系

 

 

最后咱们总结出领域建模的三字经方法:找名词、加属性、连关系。 

  

 

找名词

 

who : 学员、讲师、管理员

 

用例:

1. 管理员 建立了 北京 和 上海 两个校区

2. 管理员 建立了 Linux \ Python \ Go 3个课程 

3. 管理员 建立了 北京校区的Python 16期, Go开发第一期,和上海校区的Linux 36期 班级

4. 管理员 建立了 北京校区的 学员 小晴 ,并将其 分配 在了 班级  python 16期 

5. 管理员 建立了 讲师 Alex , 并将其分配 给了 班级 python 16期 和全栈脱产5期

6. 讲师 Alex 建立 了一条 python 16期的 上课纪录 Day6 

7. 讲师 Alex 为Day6这节课 全部的学员 批了做业 ,小晴得了A, 李磊得了C-, 严帅得了B

8. 学员小晴 在 python 16 的 day6里 提交了做业 

9. 学员李磊 查看了本身所报的全部课程 

10 学员 李磊  在 查看了 本身在 py16期 的 成绩列表 ,而后自杀了

11. 学员小晴  跟 讲师 Alex 表白了

 

 

名词列表:

管理员、校区、课程、班级、上课纪录、做业、成绩、讲师、学员

 
 

加属性

 

 

 

连关系 

有了类,也有了属性,接下来天然就是找出它们的关系了。

 


 

 
 
 

本节做业: 选课系统

角色:学校、学员、课程、讲师
要求:
1. 建立北京、上海 2 所学校
2. 建立linux , python , go 3个课程 , linux\py 在北京开, go 在上海开
3. 课程包含,周期,价格,经过学校建立课程
4. 经过学校建立班级, 班级关联课程、讲师
5. 建立学员时,选择学校,关联班级
5. 建立讲师角色时要关联学校,
6. 提供两个角色接口
6.1 学员视图, 能够注册, 交学费, 选择班级,
6.2 讲师视图, 讲师可管理本身的班级, 上课时选择班级, 查看班级学员列表 , 修改所管理的学员的成绩
6.3 管理视图,建立讲师, 建立班级,建立课程

7. 上面的操做产生的数据都经过pickle序列化保存到文件里

相关文章
相关标签/搜索