第一章 面向对象编程
面向对象语法
attack_vals = { "京巴":30, "藏獒":80 } def dog(name,d_type): # 模板 data ={"name":name, "d_type":d_type, # "attack_val":30, "life_val":100 } if d_type in attack_vals: data["attack_val"] = attack_vals[d_type] else: data["attack_val"] = 15 return data def person(name,age): data = {"name":name, "age":age, "life_val":100 } if age>18: data["attack_val"] =50 else: data["attack_val"] =30 return data def dog_bite(dog_obj,person_obj): person_obj["life_val"] -= dog_obj["attack_val"] # 执行咬人动作 print("狗[%s]咬了人[%s]一口,人掉血[%s],还有血量[%s]..."%(dog_obj['name'], person_obj['name'], dog_obj["attack_val"], person_obj["life_val"])) def beat(person_obj,dog_obj): dog_obj["life_val"] -= person_obj["attack_val"] print("人[%s]打了狗[%s]一棒,狗掉血[%s],还有血量[%s]..."%(person_obj["name"], dog_obj["name"], person_obj["attack_val"], dog_obj["life_val"])) d1 = dog("mjj","京巴") # 实体 d2 = dog("mjj2","藏獒") p1 = person("alex",22) dog_bite(d1,p1) beat(p1,d1) dog_bite(p1,d2) print(d1,d2) print(p1)
人是不应该调用狗的功能的,如何在代码级别实现这个限制呢?
attack_vals = { "京巴":30, "藏獒":80 } def dog(name,d_type): # 模板 data ={"name":name, "d_type":d_type, "life_val":100 } if d_type in attack_vals: data["attack_val"] = attack_vals[d_type] else: data["attack_val"] = 15 def dog_bite( person_obj): person_obj["life_val"] -= data["attack_val"] # 执行咬人动作 print("狗[%s]咬了人[%s]一口,人掉血[%s],还有血量[%s]..." % (data['name'], person_obj['name'], data["attack_val"], person_obj["life_val"])) data["bite"] = dog_bite # 为了从函数外部可以调用这个dog_bite方法 return data def person(name,age): data = {"name":name, "age":age, "life_val":100 } if age>18: data["attack_val"] =50 else: data["attack_val"] =30 def beat(dog_obj): dog_obj["life_val"] -= data["attack_val"] print("人[%s]打了狗[%s]一棒,狗掉血[%s],还有血量[%s]..." % (data["name"], dog_obj["name"], data["attack_val"], dog_obj["life_val"])) data["beat"] = beat return data d1 = dog("mjj","京巴") # 实体 d2 = dog("mjj2","藏獒") p1 = person("alex",22) d1["bite"](p1) # 咬人 d1["bite"](p1) # 咬人 d1["bite"](p1) # 咬人 p1["beat"](d1) # 打狗
编程范式
编程是 程序 员 用特定的语法+数据结构+算法组成的代码来告诉计算机如何执行任务的过程 , 一个程序是程序员为了得到一个任务结果而编写的一组指令的集合,正所谓条条大路通罗马,实现一个任务的方式有很多种不同的方式, 对这些不同的编程方式的特点进行归纳总结出来的编程方式类别,即为编程范式。 不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路, 大多数语言只支持一种编程范式,当然也有些语言可以同时支持多种编程范式。 两种最重要的编程范式分别是面向过程编程和面向对象编程。
面向过程 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, 就是程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题 。基本设计思路就是程序一开始是要着手解决一个大的问题,然后把一个大问题分解成很多个小问题或子过程,这些子过程再执行的过程再继续分解直到小问题足够简单到可以在一个小步骤范围内解决。
面向对象编程(Object-Oriented Programming)
OOP编程是利用“类”和“对象”来创建各种模型来实现对真实世界的描述,使用面向对象编程的原因一方面是因为它可以使程序的维护和扩展变得更简单,并且可以大大提高程序开发效率 ,另外,基于面向对象的程序可以使它人更加容易理解你的代码逻辑,从而使团队开发变得更从容。
面向对象的几个核心特性如下
Class 类
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法
Object 对象
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同
Encapsulation 封装
在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法
Inheritance 继承
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承
Polymorphism 多态
多态是面向对象的重要特性,简单点说:“一个接口,多种实现”,指一个基类中派生出了不同的子类,且每个子类在继承了同样的方法名的同时又对父类的方法做了不同的实现,这就是同一种事物表现出的多种形态。
编程其实就是一个将具体世界进行抽象化的过程,多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。
对不同类的对象发出相同的消息将会有不同的行为。比如,你的老板让所有员工在九点钟开始工作, 他只要在九点钟的时候说:“开始工作”即可,而不需要对销售人员说:“开始销售工作”,对技术人员说:“开始技术工作”, 因为“员工”是一个抽象的事物, 只要是员工就可以开始工作,他知道这一点就行了。至于每个员工,当然会各司其职,做各自的工作。
多态允许将子类的对象当作父类的对象使用,某父类型的引用指向其子类型的对象,调用的方法是该子类型的方法。这里引用和调用方法的代码编译前就已经决定了,而引用所指向的对象可以在运行期间动态绑定
面向对象vs面向过程总结
面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。
优点是:极大的降低了写程序的复杂度,只需要顺着要执行的步骤,堆叠代码即可。
缺点是:一套流水线或者流程就是用来解决一个问题,代码牵一发而动全身。
面向对象的程序设计的核心是对象(上帝式思维),要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。面向对象的程序设计好比如来设计西游记,如来要解决的问题是把经书传给东土大唐,如来想了想解决这个问题需要四个人:唐僧,沙和尚,猪八戒,孙悟空,每个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的属性和方法),然而这并不好玩,于是如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。然后取经开始,师徒四人与妖魔鬼怪神仙互相缠斗着直到最后取得真经。如来根本不会管师徒四人按照什么流程去取。
面向对象的程序设计的
优点是:解决了程序的扩展性。对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。
缺点:可控性差,无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法预测最终结果。于是我们经常看到一个游戏人某一参数的修改极有可能导致阴霸的技能出现,一刀砍死3个人,这个游戏就失去平衡。
应用场景:需求经常变化的软件,一般需求的变化都集中在用户层,互联网应用,企业内部软件,游戏等都是面向对象的程序设计大显身手的好地方。
类的定义
继承
# coding=utf-8 class Animal: a_type = "哺乳动物" def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex print("---父类的构造方法") def eat(self): print("%s is eating..."% self.name) class Person(Animal): # 继承 a_type = "哺乳高等动物" def __init__(self,name,age,sex,hobby): # Animal.__init__(self,name,age,sex) super(Person, self).__init__(name,age,sex) # 效果同上 self.hobby = hobby print("---子类的构造方法") def talk(self): print("person %s is talking...." % self.name) def eat(self): Animal.eat(self) # 先执行父类再执行子类方法 print("人在优雅的吃饭。。。") class Dog(Animal): def chase_rabbit(self): print("狗在追兔子。。。") p = Person("Alex",22,"M","女人") # 生成实例 p.eat() # 调用父类方法 p.talk() print(p.a_type) print(p.name,p.sex,p.hobby) d = Dog("Mjj",3,"Female") d.eat() d.chase_rabbit() # 调用子类自有的方法
校园管理系统
设计一个培训机构管理系统,有总部、分校,有学员、老师、员工,实现具体如下需求:
1.有多个课程,课程要有定价
2.有多个班级,班级跟课程有关联
3.有多个学生,学生报名班级,交这个班级对应的课程的费用
4.有多个老师,可以分布在不同校区,上不同班级的课
5.有多个员工,可以分布在不同校区在总部可以统计各校区的账户余额、员工人数、学员人数
6.学生可以转校、退学
思路:
1,定模型,多少个类
1)找出关键独立名词:
总部
分校
学员
老师
员工
课程
班级
2,定属性
总部:名称、地址、电话、网址
财务账户
员工列表
学员列表人数
发工资
开分校
招人
分校:
pass
学员:姓名、年龄、班级、余额
上学打卡
交学费
老师:教学
员工:姓名、职务、部门、工资
课程:名称、大纲、价格
班级:课程、学期、学员列表,校区
3,定关系
分校---》总部
学员--》班级
班级--》校区
老师--》班级
老师--》员工
学员--》老师
员工--》校区
4,画UML模型图
统一建模语言
5,写代码
# coding=utf-8 import datetime class School(object): """总部学校类""" def __init__(self, name, addr, website): self.name = name self.addr = addr self.website = website self.balance = 0 self.branches = [] # 存所有分校对象 self.class_list = [] # 存放班级列表 self.staff_list = [] # 存放员工列表 print("创建了校区[%s],地址[%s]" % (name, addr)) def count_stu_num(self): pass def count_stuff_num(self): pass def staff_enrollment(self, staff_obj): self.staff_list.append(staff_obj) print("[%s]入职新员工[%s],职位[%s],部门[%s]"%(self.name,staff_obj.name,staff_obj.position,staff_obj.dept)) def count_total_revenue(self): print("----校区总收入----") total_rev = self.balance print(self.name,self.balance) for b in self.branches: print(b.name,b.balance) total_rev += b.balance print("校区总收入:%s"%total_rev) def count_class_list(self): print("---各校区班级---") print(self.name,self.class_list) for i in self.branches: print(i.name, i.class_list) def pay_salary(self): print("开始发工资啦。。。") for i in self.staff_list: i.balance += i.salary # 发工资 self.balance -= i.salary # 总部相应账户扣钱 print("给%s发了%s,他的余额:%s"%(i.name,i.salary,i.salary)) print("公司的余额",self.balance) def __str__(self): return self.name def __repr__(self): return self.name class BranchSchool(School): """分校""" def __init__(self,name,addr,website,headquarter_obj): super().__init__(name,addr,website) self.headquarter = headquarter_obj # 总部的对象 self.headquarter.branches.append(self) # 把自己加入到总校的校区列表,建立总部---》分校的反向关联 class Course(object): """课程类""" def __init__(self, name, price, outline): self.name = name self.price = price self.outline = outline print("创建了课程[%s],学费[%s]" % (name, price)) class Class(object): """班级""" def __init__(self, course_obj, semester, school_obj): self.course_obj = course_obj self.semester = semester self.school_obj = school_obj self.stu_list = [] # 存放学员列表 school_obj.class_list.append(self) # 把自己加到校区的班级列表 print("校区[%s]创建了班级[%s],学期[%s]" % (school_obj.name, course_obj.name, semester)) def stu_transfer(self, stu_obj, new_class_obj): """ 学员转校 :param stu_obj: 学员对象 :param new_class_obj: 转到的新班级的对象 :return: """ def __str__(self): return "%s-%s-%s学期" % (self.school_obj.name, self.course_obj, self.semester) def __repr__(self): return "%s-%s-%s学期" % (self.school_obj.name, self.course_obj, self.semester) class Staff(object): """员工""" def __init__(self, name, age, balance, salary, position, dept, school_obj): self.name = name self.age = age self.balance = balance self.salary = salary self.position = position self.dept = dept self.school_obj = school_obj school_obj.staff_enrollment(self) # 办入职 def punch_card(self): pass class Teacher(Staff): def __init__(self, name, age, balance, salary, position, dept, school_obj, course_obj): super().__init__(name, age, balance, salary, position, dept, school_obj) self.course_obj = course_obj # 老师可以讲的课 def teach_class(self, class_obj, day): print("老师[%s]正在班级[%s]上第[%s]天课ing" % (self.name, class_obj, day)) class Student(object): """学员""" def __init__(self, name, age, balance, class_obj): self.name = name self.age = age self.balance = balance self.class_obj = class_obj # 加入班级 class_obj.stu_list.append(self) # 交学费 class_obj.school_obj.balance += class_obj.course_obj.price self.balance -= class_obj.course_obj.price print("班级[%s]加入了新学员[%s],交了学费[%s]" % (class_obj, name, class_obj.course_obj.price)) def punch_card(self): print("%s:学员在班级[%s]上课了...." % (datetime.datetime.now(), self.class_obj)) # 创建校区 headquarter = School("老男孩IT教育集团", "北京昌平沙河", "oldboyedu.com") sh1_school = BranchSchool("张江校区", "上海张江", "oldboyedu.com",headquarter) sh2_school = BranchSchool("虹桥校区", "上海虹桥火车站", "oldboyedu.com",headquarter) sz1 = BranchSchool("骑士计划", "深证大学城", "oldboyedu.com",headquarter) luffy = BranchSchool("路飞学城", "北京长安街", "luffycity.com",headquarter) # 创建课程 py_course = Course("Python",21800, None) linux_course = Course("linux", 19800, None) test_course = Course("Testing", 19800, None) go_course = Course("GO", 22800, None) # 创建班级 py_24 = Class(py_course, 24, headquarter) go_5 = Class(go_course, 5, headquarter) py_12 = Class(py_course, 12, sh1_school) linux_63 = Class(linux_course, 63, sz1) # 创建员工,老师,学员 s1 = Staff("Alex", 26, 0, 4000, "CEO", "总经办", luffy) s2 = Staff("Todd", 45, 0, 60000, "CEO", "总经办", headquarter) s3 = Staff("明月", 24, 0, 7000, "HR", "HR", headquarter) t1 = Teacher("日天", 28, 0, 30000, "讲师", "教学部", sz1, py_course) t2 = Teacher("Egon", 28, 0, 30000, "讲师", "教学部", sh1_school, go_course) t3 = Teacher("佩奇", 29, 0, 40000, "学科带头人", "教学部", headquarter, linux_course) stu1 = Student("春生", 22, 50000, py_24) stu2 = Student("black_girl", 22, 30000, go_5) stu3 = Student("小强", 22, 35000, go_5) stu4 = Student("小虎", 28, 38000, linux_63) print(headquarter.balance) print(sz1.balance) print(headquarter.branches) # 统计总收入,学员人数 headquarter.count_total_revenue() headquarter.count_class_list() headquarter.pay_salary()