“面向对象”是专指在程序设计中采用封装、继承、抽象等设计方法。可是,这个定义显然不能再适合现在情况。面向对象的思想已经涉及到软件开发的各个方面。如,面向对象的分析(OOA,Object Oriented Analysis),面向对象的设计(OOD,Object Oriented Design)、以及我们经常说的面向对象的编程实现(OOP,Object Oriented Programming)面向对象是一种新兴的程序设计方法,或者说它是一种新的程序设计范型,其基本思想是使用对象,类,继承,封装,消息等基本概念来进行程序设计。
给你一个任务,你要思考怎么做。
如果你的思维方式是:我先做什么,再做什么……这叫面向过程;
如果思维方式是:我先做一个什么东西来做这件事,再做一个什么东西来做那件事,然后它们怎么相互配合……这叫面向对象。
封装
封装就是定义一个类,然后给该类的 属性(成员变量) 和方法加上访问控制,使得该类的属性和方法对于类外部来说,想可见的可见,不想可见的隐藏。所以,通过封装这个手段,就抽象出来了事物的本质特性。
将对象敏感的数据,封装在类的内部,不让外界直接访问;而是通过定义的set/get方法来间接访问内部的数据的过程,此时,就可以在set/get方法中,添加条件限制代码!�正常变量,没有任何限制,想怎么访问怎么访问‚约定了以一个下划线开头的变量,是私有变量,外界不要直接使用,如_nameƒ两个下划线开头的属性,表示当前类的私有属性,外界不能访问__age
classPerson:
def__init__(self,heigh,name, age):
self.heigh = heigh
self._name = name
self.__age = age
defset_age(self, age):
ifage >=0andage <=100:
self.__age = age
else:
print("设置的年龄不合法...")
defget_age(self):
returnself.__age
def__str__(self):
return"姓名:%s;年龄:%s"% (self.__name,self.__age)
p = Person(175,"tom",12)
print(p.heigh)
print(p._name)可以输出,但不建议
print(p.__age)报错,会出现不存在__age的说法,应该应用一下用法:
p.set_age(1200)
print(p。Get_age)
对上面进行进一步的解释:
所谓封装,就是将属性和方法捆绑到一起,封装到一个对象中去,简单的说,你是人,你有许多属性,比如说你的姓名,年龄,身高,体重,性别,性格,爱好等等,这是属性;而同时,你又会吃饭,睡觉,工作,学习,做事情,这些是方法,是你所具有的;同时将属性和方法封装到一个类中去,就能很完美的描述这个类的特征了,同时,它所具有的方法也就一起集成到类中,方便使用。
为什么要加上访问控制?
一是,有些东西是很关键很机密的,不想随便被使用,被改变,被访问。
二是,可能这个东西不是很关键机密,访问和改变也无所谓,但是,因为有些属性和方法,它们对于外部来说,是无关的没用的,但是对于我自己这个类来说,是必要的,因为可能在我自己这个类中要使用它们,这个时候,进行隐藏,不让外部看,好处就是,如果将这些不必要的内容也暴露给外部的话,那么在使用的时候,使用者会被迷惑,因为这个东西对他没用,但是又可以调用,访问,而且他又不知道又没有用,但是如果进行隐藏,不给外部查看,那么就很清晰了,因为这样一来,只要是对外暴露的属性方法,都是有用的,你想一下,JDK的类库里面的那些类,比如String类,对外暴露的属性和方法,哪个是无用的?这也是一种良好的编程习惯和规范。
封装是把过程和数据包围起来,对数据的访问只能通过已定义的界面。面向对象计算始于这个基本概念,即现实世界可以被描绘成一系列完全自治、封装的对象,这些对象通过一个受保护的接口访问其他对象。(采自Java面试题)
继承
继承是指一个对象直接使用另一对象的属性和方法。继承可以使得子类具有父类的各种属性和方法,而不需要再次编写相同的代码。在令子类继承父类的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类的原有属性和方法,使其获得与父类不同的功能。
同类事物具有共同性,在同类事物中,每个事物又具有其特殊性。运用抽象的原则舍弃对象的特殊性,抽取其共同性,则得到一个适应于一批对象的类,这便是基类(父类),而把具有特殊性的类称为派生类(子类),派生类的对象拥有其基类的全部或部分属性与方法,称作派生类对基类的继承。语法层面上讲,继承就是派生类拥有父类的数据、方法,又添了点自己的东西,所谓子承父业,发扬光大。
父类:被继承的类,称为父类,也称为基类、超类,子类继承父类,父类还可以继承父类
子类:继承了父类的类,称为子类,也称为派生类
子类拥有父类的公共属性和公共方法,如下面代码:
classA:
defeat(self):
print("吃饭")
classB(A):
defplay(self):
print("游戏中...")
classC(B):
defsleep(self):
print("休息休息")
classD(C):
pass
d = D()
d.eat()代码中B拥有A的方法,C拥有A,B的方法,D拥有ABC的方法
d.play()即D继承了以上父类的所有方法
d.sleep()
一个子类,可以同时继承多个父类
多继承,反应了生活中表现的多个角色如下面代码:
#定义了一个基础类
classPerson(object):
def__init__(self):
self.name ="tom"
classStudent(Person):
defeat(self):
print("吃食堂....")
defrespect(self):
print("尊师重道")
classSon(Person):
defeat(self):
print("吃美食...")
deffealty(self):
print("尊老爱幼")
# User类型,继承了儿子类型、学生类型
#同时拥有儿子类型和学生类型中所有的公共属性和方法
classUser(Son,Student):
pass
#创建对象
u = User()
u.respect()# u是学生角色
u.fealty()# u是儿子角色
对于吃饭这个方法,如果继承的多个父类中,出现了相同的属性和方法,就会执行方法或者属性的搜索过程,搜索到对应的属性和方法,立即执行,中断搜索所以尽量不要在多个类中出现名称相同的属性和方法
属性和方法的搜索过程,可以通过 类型.__mro__魔法属性进行查看,
基本原则是:优先继承,优先执行
u.eat()#即执行son的角色
print(User.__mro__)# method from object
方法重写:子类中,重新定义父类中已经存在的方法 子类-父类,两个实现了继承关系的类型,才会有方法重写如果方法进行了重写,在子类对象执行这个方法时,优先执行重写的方法。如果子类没有重写这个方法,在执行时就会执行从父类中继承过来的方法
classPerson:
defeat(self,food):
print("吃饭吃饭..饿肚肚..吃%s"% food)
classMan(Person):
defeat(self,food):
print(">>>>>>>>>>饿肚肚,吃饭饭,吃%s"% food)
p = Person()
p.eat("鱼香肉丝")
m = Man()
m.eat("烤全羊")#优先执行自身的方法的代码
方法重载:在一个类型中,出现了相同名称,不同参数的函数/方法,称为方法重载
目的:在执行的过程中,通过参数的不同,来执行不同的代码,实现不同的功能
python中,已经实现了,【可变参数、关键字参数】--【我不需要方法重载了!】
python又针对属性访问函数,进行了相同名称函数的定义 —— 伪方法重载
伪方法重载的目的:配合封装,隐藏数据访问方法的底层实现!
在下面代码讲解
classUser:
def__init__(self,name):
self.__name = name
@property
defname(self):
returnself.__name
@name.setter#旁边执行了两个name方法,即叫做(伪)方法重载
defname(self,n):
self.__name = n
u = User("tom")
u.name ="jerry"#数据访问方法被隐藏了,方法当成了属性来进行执行
print(u.name)#数据访问方法被隐藏了,方法当成了属性来进行执行
多态
多态:程序在运行的过程中,根据执行条件的不同,动态执行不同的操作代码的过程称为程序运行时多态。请看一下程序
#定义一个人的类型
classPerson:
# name姓名age年龄health健康值【0~50极度虚弱,51~70亚健康,71~85健康,86~100强壮】
def__init__(self,name,age,health):
self.name = name
self.age = age
self.health = health
#康复的方法
defrecure(self):
print("[%s]康复了,当前健康值%s"% (self.name,self.health))
classMan(Person):
def__init__(self,name,age,health):
Person.__init__(self,name,age,health)
defrecure(self):
print("%s哇咔咔,康复了"%self.name)
classWomen(Person):
def__init__(self,name,age,health):
Person.__init__(self,name,age,health)
defrecure(self):
print("[%s]死鬼,终于康复了..."%self.name)
classAnimal:
# name姓名age年龄health健康值【0~50极度虚弱,51~70亚健康,71~85健康,86~100强壮】
def__init__(self,name,age,health):
self.name = name
self.age = age
self.health = health
#康复的方法
defrecure(self):
print("[%s]嘿嘿嘿,终于康复了,当前健康值%s"% (self.name,self.health))
#定义人民医院
classHospital:
def__init__(self):
self.name ="人民医院"
defcare(self,person):
#类型判断,判断变量person是否Person类型
ifisinstance(person,Person):
ifperson.health >0andperson.health <=50:
print("手术......")
person.health +=30
person.recure()
elifperson.health >50andperson.health <=70:
print("输液......")
person.health +=15
person.recure()
else:
print("健康")
else:
print("不好意思,请出门左转,哪里是兽医院")
#医院对象
hospital = Hospital()
#生病的人
old_wang = Person("王先生",58,30)
mrs_li = Women("李夫人",28,56)
mr_li = Man("李先生",30,60)
#在这里,hospital由于对象的不同执行不同的
代码动态执行不同的操作代码的过程称为程序运行时多态
hospital.care(mrs_li)
#调用了治疗的方法
hospital.care(old_wang)
hospital.care(mr_li)
a = Animal("tom",22,10)
hospital.care(a)
执行结果:
手术......
[王先生]康复了,当前健康值60
输液......
[李夫人]死鬼,终于康复了...
输液......
李先生哇咔咔,康复了
不好意思,请出门左转,哪里是兽医院
Process finished with exit code 0
再来一个例子:
classMan:
defintro(self):
print("我的姓名是XXXXXXXXXXXXXXXXXXXXXX")
classWomen:
defintro(self):
print("我的姓名是oooooooooooooooooooooo")
defintroduction(person):
person.intro()
m = Man()
w = Women()
introduction(m)#由于m和w的不同,函数执行两个不同代码,这个过程就可以
introduction(w)#称之为多态