编程范式主要分为面向过程及面向对象.
面向过程(Procedural Programming)
程序从上到下一步步执行, 一步步从上到下, 从头到尾的解决问题 . 基本设计思路就是程序一开始是要着手解决一个大的问题, 然后把一个大问题分解成很多个小问题或子过程, 这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决. 但这样做有个问题, 当程序开头定义了一个值为 1 的变量, 后面的子过程必须依赖这个变量, 当修改该变量时所有依赖这个变量的子过程都要更改, 假如又有一个其他子程序依赖这个子过程, 就会发生一系列的影响. 如果写简单的脚本用面向过程的范式简单直接, 而在做复杂的任务并且以后需要不断维护时, 还是用面向过程最方便.
面向对象(Object-Oriented Programming)
面向对象是通过 "类" 以及 "对象" 来创建各种模型来实现对真实世界的描述, 使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单, 并且可以大大提高程序开发效率. 并且极大的提高了程序的可读性(维护人员在读面向过程的程序是必须从头开始, 而面向过程的程序只需了解对对象的操作就可以了)
无论用什么形式来编程, 要记住一下原则:
1. 写重复代码是非常不好的低级行为. 如果把一段代码复制, 粘贴在程序多个地方调用, 日后在对该功能修改时需要把程序中多个地方都改一遍, 如果遗漏一处可能导致整个程序的运行出现问题, 因此我们在写代码时一定要努力避免写重复的代码, 否则相当于给自己挖坑.
2. 写的代码需要经常变更 开发正规程序跟写小的脚本 (用完一次就扔) 的区别是代码需要不停的更改, 不是修改 bug 就是添加新的功能, 所以为了方便程序的修改及扩展, 写代码一定要遵循易读, 易改的原则.
用面向对象的编程范式就可规避上述的坑!
面向对象的核心内容:
Class 类
一个类即是对一类拥有相同属性的对象的抽象, 蓝图, 原型. 在类中定义了这些对象的都具备的属性(variables(data)), 共同的方法
Object 对象
一个对象即是一个类的实例化后实例, 一个类必须经过实例化后方可在程序中调用, 一个类可以实例化多个对象, 每个对象亦可以有不同的属性, 就像人类是指所有人, 每个人是指具体的对象, 人与人之前有共性, 亦有不同
Encapsulation 封装
在类中对数据的赋值, 内部调用对外部用户是透明的, 这使类变成了一个胶囊或容器, 里面包含着类的数据和方法
Inheritance 继承
一个类可以派生出子类, 在这个父类里定义的属性, 方法自动被子类继承
Polymorphism 多态
多态是面向对象的重要特性, 简单点说:"一个接口, 多种实现", 指一个基类中派生出了不同的子类, 且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现, 这就是同一种事物表现出的多种形态.
编程其实就是一个将具体世界进行抽象化的过程, 多态就是抽象化的一种体现, 把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话.
对不同类的对象发出相同的消息将会有不同的行为. 比如, 你的老板让所有员工在九点钟开始工作, 他只要在九点钟的时候说:"开始工作" 即可, 而不需要对销售人员说:"开始销售工作", 对技术人员说:"开始技术工作", 因为 "员工" 是一个抽象的事物, 只要是员工就可以开始工作, 他知道这一点就行了. 至于每个员工, 当然会各司其职, 做各自的工作.
多态允许将子类的对象当作父类的对象使用, 某父类型的引用指向其子类型的对象, 调用的方法是该子类型的方法. 这里引用和调用方法的代码编译前就已经决定了, 而引用所指向的对象可以在运行期间动态绑定.
我们现在来比较一下两种编程的范式的区别, 现在来做一个吃鸡的游戏, 定义角色 1 和角色 2, 然后把一些功能写成函数
- Role ={
- 1:{'name':'吃鸡小王子',
- 'weapon1':'98k',
- 'weapon2':'Scarl',
- 'life_value':100,
- 'kill_person':0,
- },
- 2:{'name':'伏地魔',
- 'weapon1':'98k',
- 'weapon2':'Scarl',
- 'life_value':100,
- 'kill_person':0,
- },
- }
- def got_shot(role):
- role['life_value']-=20 #当在定义角色的时候如果把 life_value 写错, 调用该函数就会出问题
- print('%s got shot!'%role['name'])
- pass
- def change_weapon1(role,weapon):
- role['weapon1']=weapon
- def change_weapon2(role,weapon):
- role['weapon2']=weapon
- got_shot(Role[1])
这就是面向过程的设计思路, 至少可以发现这些缺陷,
1. 每个角色定义的属性名称是一样的, 但属性的命名规则是我们自己定的, 没有进行属性合法性检测, 如果在新增角色的时候把 life_value 写成 life_calue, 在进行程序调用的时候就会出现 bug.
2. 按理说只有被击中以后调用 got_shot 函数来减血, 但我们可以直接改变 role1["life_value"]变量的值来改变血值. 因此在这里必须设计成只能通过 got_shot 来减血, 但在上述过程是无法实现的.
3. 现在需要给每个角色加一件甲, 则需要在在每个角色里放置一个新的属性来存储该角色是三级甲还是二级甲, 那就需要更改每个角色的代码来添加新的属性, 不符合代码可重复用的属性.
我们用 oop 的方式来完成这个游戏
- class Role: #定义类
- def __init__(self,name,weapon1,weapon2,life_value=100,kill_person=0):
- self.name = name #实例变量(静态属性), 作用域是实例本身, 未实例化是不能使用.
- self.weapon1 = weapon1
- self.weapon2 = weapon2
- self.life_value = life_value
- self.kill_person = kill_person
- def got_shot(self):
- self.life_value-=20
- print('%s got shot!'%self.name)
- def change_weapon1(self,weapon):
- print("drop%s and get %s" % (self.weapon1, weapon))
- self.weapon1 = weapon
- def change_weapon2(self,weapon):
- print("drop%s and get %s" % (self.weapon2, weapon))
- self.weapon2 = weapon
- role1 = Role("吃鸡小王子","98K","M416") #生成角色(实例化
- role2 = Role("伏地魔","Scarl","平底锅")
- role1.change_weapon1("AK")
- role1.got_shot()
先不考虑细节, 相比面对过程的方法, 最直接的优点有下面几点:
1. 代码量少了很多
2. 角色的属性和功能一目了然.
来源: http://www.bubuko.com/infodetail-2851324.html