首页 > 代码库 > 面向对象

面向对象

编程范式:

编程是 程序员 用 “特定的语法+数据结构+算法组成的代码”来告诉 计算机 如何执行任务的过程。

通过对不同的编程方式的特点的归纳总结出来的编程方式类别就是 编程范式。

不同的编程范式本质上代表队各种类型的任务采取的不同的解决问题的思路,大多数语言只支持一种编程范式,当然也有些语言可以同时支持多种编程范式。两种最重要的编程范式分别是面向过程编程和面向对象编程。


面向过程编程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.测试备份文件可用性。

代码如下:

  1. def db_conn():
  2. print(‘connecting db...‘)
  3. def db_backup(dbname):
  4. print(‘导出数据库...‘,dbname)
  5. print(‘将备份文件打包,移至相应目录‘)
  6. def db_backup_test():
  7. print(‘将备份文件导入测试库,看导入是否成功‘)
  8. def main():
  9. db_conn()
  10. db_backup(‘my_db‘)
  11. db_backup_test()
  12. if __name__==‘__main__‘:
  13. main()
这样做的问题也是显而易见的,就是如果你要对程序进行修改,对你修改的那部分有依赖的各个部分你都也要跟着修改,举个例子,如果程序开头你设置了一个变量值为1,但如果其他子过程以来这个值为1的变量才能正常运行,那如果你改了这个变量,那这个子过程你也要修改。即使又有一个子过程依赖这个子过程,那就会发生一连串的影响,随着程序越来越大,这种编程方式的维护难度会越来越高。
所以我们一般认为,如果你只是写一些简单的脚本,去做一些一次性任务,用面向过程的方式是极好的,但如果你要处理的任务是复杂的,且需要不断迭代和维护的,那还是用面向对象最方便了。


面向过程的优势:简单的或者一次性的脚本文件或程序用面向过程编程,效率相对更高。
面向过程的劣势:正式地生产环境中使用的程序或经常需要扩展的程序,后期的维护成本远远高于面向对象。


面向对象编程Object Oriented Programming

面向对象的概念架构

类class
属性attribute
实例变量:对象私有,某一个对象将其值改变,不影响其他对象
类变量:是所有对象共有,其中一个对象对它值改变,其他对象得到的就是改变后的结果
私有属性__var
方法def func(self):
构造方法__init__(self)
析构函数__del__(self)
私有方法__func(self)
对象:实例化一个类之后得到的对象object=Class()
封装
把一些功能的实现细节不对外暴露

继承
继承 ,组合

代码的重用
单继承
多继承,
2.7 经典类,深度优先, 新式类,广度优先
3.x 均是广度优先
class Foo(object):
def __init__(self,name,age,sex,salary,course):

self.salary = salary
self.course = course

多态
接口重用, 一种接口,多种实现

静态方法
只是名义上归类管理, 实际上在静态方法里访问不了类或实例中的任何属性
类方法
只能访问类变量,不能访问实例变量

属性方法
把一个方法变成一个静态属性

定义:

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

“类”“对象”创建各种模型实现对真实世界的描述——世界万物,皆可分类;世界万物,皆为对象。

 


面向对象的几个核心特性:封装、继承、多态

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

Object 对象 
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同.

  只要是对象,就肯定属于某种品类;

  只要是对象,就肯定有属性。

Encapsulation 封装

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

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

封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。

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

Polymorphism 多态

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


如何理解和使用面向对象编程

原则:

1.写重复代码是非常不好的低级行为

2.代码需要经常变更


开发正规的程序和一次性的小脚本一个很大的不同就是,程序的代码需要不断地变更,不是修改bug就是添加新功能等,所以为了日后方便程序的修改及扩展,你写的代码一定要遵循易读、易改的原则(专业数据叫可读性好、以扩展)。

在开发中一定要努力避免写重复的代码,都这就相当于给自己再挖坑。

函数能够帮我们解决重复的代码问题,对于需要重复调用的功能,只需要把它写成一个函数,然后再程序的各个地方直接调用这个函数名就好了,并且当需要修改这个功能时,只需改函数代码,然后整个程序都更新了。

OOP编程的主要作用也是使你的代码修改和扩展变得更容易。函数编程与OOP的主要区别就是OOP可以使程序更加容易扩展和易更改。



类的语法及封装:

  1. class Dog(object):#定义一个类,Role是类名,(object)是新式类的写法,必须这样写
  2. def __init__(self,name,dog_type): #构造方法(初始化方法),在实例化时做一些类的初始化的工作
  3. ‘__init__()方法虽然是函数形式,但是类中就不叫函数了,叫方法,会自动执行,进行一些初始化的动作‘
  4. self.name=name #实例变量(静态属性),作用域就是实例本身
  5. self.dog_type=dog_type
  6. def sayhi(self): #类的方法,功能(动态属性)
  7. print(‘hello,I am a dog! My name is %s‘% self.name)
  8. d=Dog(‘dingding‘,‘京巴‘) #实例化这个类,相当于Dog(d,‘dingding‘,‘京巴‘)
  9. #此时的d就是类Dog的实例化对象
  10. #生成一个角色,会自动把参数传给Role下面的__init__(...)方法
  11. #实例化,其实就是以Dog为模板,在内存里开辟一块空间,存上数据,赋值成一个变量名。
如果直接打印:
  1. print(Dog)
输出如下:
    <class ‘__main__.Dog‘>

这个代表,即使不实例化,这个Dog类本身也是已经存在内存里。

下图是实例化在内存中的实现过程:

技术分享

 

由上图得知,其实self,就是实例本身!实例化时python会自动把这个实例本身通过self参数传进去。

实例化 d=Dog(‘dingding‘,‘京巴‘) 时,Python解释器做了两件事:

    1.在内存中开辟一块空间指向d这个变量名

    2.调用Dog这个类并执行其中__init__(...)方法,相当于Dog.__init__(d,‘dingding‘,‘京巴‘)———

        目的在于把‘dingding‘,‘京巴‘这两个值和刚开辟的d关联起来。

        关联起来后,就可以直接用d.name,d.dog_type来调用了。

        所以,为了实现这种关联,在调用__init__()方法时,必须把d这个变量也传进去,否则__init__不知道要把那3个参数跟谁关联。

so,__init__()方法里的,self.name=name,self.dog_type=dog_type是要把这几个值存到d的内存空间里。


上面介绍的都是类的静态属性在内存中的实现方法和实现过程,下面介绍类的动态属性(类的函数)是如何调用的。

在调用类的一个方法时,得告诉该方法你是谁:

  1. d=Dog(‘dingding‘,‘京巴‘) #实例化这个类
  2. d.sayhi() #Dog.sayhi(d) #self.name相当于调用d.name

总结:

  1. 上面的这个d=Dog(‘dingding‘,‘京巴‘)动作,叫做类的“实例化”, 就是把一个虚拟的抽象的类,通过这个动作,变成了一个具体的对象了, 这个对象就叫做实例
  2. 刚才定义的这个类体现了面向对象的第一个基本特性,封装其实就是使用构造方法将内容封装到某个具体对象中,然后通过对象直接或者self间接获取被封装的内容。
 


Inheritance 继承
面向对象编程 (OOP) 语言的一个主要功能就是“继承”。

继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

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

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

继承的过程,就是从一般到特殊的过程。

要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。

在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
继承概念的实现方式主要有2类:实现继承、接口继承。
    实现继承是指使用基类的属性和方法而无需额外编码的能力;
    接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构父类方法);
注意:
在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Employee 是一个人,Manager 也是一个人,因此这两个类都可以继承 Person 类。但是 Leg 类却不能继承 Person 类,因为腿并不是一个人。

抽象类仅定义将由子类创建的一般属性和方法。
OOP开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。

继承示例:

  1. class SchoolMember(object):
  2. members=0 #初始学校人数为0
  3. def __init__(self,name,age):#构造方法
  4. self.name=name
  5. self.age=age
  6. def tell(self):
  7. pass
  8. def enroll(self):
  9. ‘‘‘注册‘‘‘
  10. SchoolMember.members+=1
  11. print(‘\033[32;1mmember [%s] is enrolled,now there are [%s] members.\033[0m‘%(self.name,SchoolMember.members))
  12. def __del__(self):
  13. ‘‘‘析构方法‘‘‘
  14. print(‘\033[31;1mmember [%s] is dead!\033[0m‘%self.name)
  15. class Teacher(SchoolMember):
  16. def __init__(self,name,age,course,salary):
  17. super(Teacher,self).__init__(name,age)
  18. self.course=course
  19. self.salary=salary
  20. self.enroll()
  21. def teaching(self):
  22. ‘‘‘讲课方法‘‘‘
  23. print(‘Teacher [%s] is teaching [%s] for class [%s]‘%(self.name,self.course,‘s12‘))
  24. def tell(self):
  25. ‘‘‘自我介绍方法‘‘‘
  26. msg=‘‘‘
  27. Hi,my name is [%s], works for [%s] as a [%s] teacher!‘‘‘%(self.name,‘Oldboy‘,self.course)
  28. class Student(SchoolMember):
  29. def __init__(self,name,age,grade,sid):
  30. super(Student,self).__init__(name,age)
  31. self.grade=grade
  32. self.sid=sid
  33. self.enroll()
  34. def tell(self):
  35. ‘‘‘自我介绍方法‘‘‘
  36. msg=‘‘‘Hi,my name is [%s],I‘m studying [%s] in [%s]!‘‘‘%(self.name,self.grade,‘Oldboy‘)
  37. if __name__==‘__main__‘:
  38. t1=Teacher(‘Alex‘,22,‘Python‘,2000)
  39. t2=Teacher(‘TengLen‘,29,‘Linux‘,3000)
  40. s1=Student(‘Qinghua‘,24,‘Python S14‘,1483)
  41. s2=Student(‘SanJiang‘,26,‘Python S14‘,1484)
  42. t1.teaching()
  43. t2.teaching()
  44. t1.tell()


领域模型

领域建模是面向对象设计利器。

从领域模型开始,我们就开始了面向对象的分析和设计过程,可以说,领域模型是完成从需求分析到面向对象设计的一座桥梁。

领域模型,就是需求所涉及的领域的一个建模,更通俗的讲法是业务模型。

领域模型的定义:

    领域模型是对领域内的概念类或现实世界中对象的可视化表示。也叫业务对象模型,是描述业务用例实现的对象模型。它是对业务角色和业务实体之间应该如何联系和协作以执行业务的一种抽象。

领域模型的作用:

    1.发掘重要的业务领域概念

    2.建立业务领域概念之间的关系

领域建模三字经:‘找名词’,‘加属性’,‘连关系’

    领域建模的方法就是“从用例中找名词”。找到名词后,为了能够更加符合面向对象的要求和特点,我们还需要对这些名词进一步完善,这就是接下来的步骤:

    加属性,连关系!

    


















实例:

  1. class Role(object):#class Role(object):是新式类; class Role:是标准类
  2.     #a=1 变量直接在类下面的是类变量,属于所有该类产生的对象。
  3. def __init__(self,name,role,weapon,life_value=100,money=15000): #__init__(self)是构造函数(构造方法)
  4. self.name=name #实例变量
  5. self.role=role
  6. self.weapon=weapon
  7. self.life_value=100
  8. self.money=money
  9. def shot(self):
  10. print(‘shooting...‘)
  11. def get_shot(self):
  12. print(‘ah...,I got shot...‘)
  13. def buy_gun(self,gun_name):
  14. print(‘just bought %s‘%gun_name)
  15. r1=Role(‘Alex‘,‘police‘,‘AK47‘) #实例化(初始化一个类,造了一个对象)
  16. #把一个类变成一个具体对象的过程叫 实例化
  17. r2=Role(‘Jack‘,‘terrorist‘,‘B22‘) #实例化,生成一个角色
通过面向对象写这个程序,比通过函数拼凑出来的写法:
    1.代码量减少
    2.角色和它所具有的功能可以一目了然看出来





null


面向对象