对象间的交互
在游戏中有很多玩家,他们互砍,如何实现的?
还记得我们开头的引子么,人狗大战,用面向对象如何实现?
class Dog: # 定义一个狗类
role = 'dog' # 狗的角色属性都是狗
def __init__(self, name, breed, attack_val):
self.name = name
self.breed = breed # 每一只狗都有自己的品种;
self.attack_val = attack_val # 每一只狗都有自己的攻击力;
self.life_val = 100 # 每一只狗都有自己的生命值;
def bite(self, person):
# 狗可以咬人,这里传递进来的person也是一个对象。
person.life_val -= self.attack_val # 狗咬人,那么人的生命值就会根据狗的攻击力而下降
print("狗[%s]咬了人[%s],人掉血[%s],还剩血量[%s]..." % (self.name,person.name,self.attack_val,person.life_val))
class Person: # 定义一个人类
role = 'person' # 人的角色属性都是人
def __init__(self, name, sex, attack_val):
self.name = name
self.attack_val = attack_val
self.life_val = 100
self.sex = sex
def attack(self,dog):
# 人可以攻击狗,这里传递进来的dog也是一个对象。
# 人攻击狗,那么狗的生命值就会根据人的攻击力而下降
dog.life_val -= self.attack_val
print("人[%s]打了狗[%s],狗掉血[%s],还剩血量[%s]..." % (self.name,dog.name,self.attack_val,dog.life_val))
d = Dog("mjj","二哈",20)
p = Person("Alex","Male",60)
d.bite(p) # 对象交互,把p实例传递给d的方法
p.attack(d)
类与类之间的关系
大千世界, 万物之间皆有规则和规律. 我们的类和对象是对大千世界中的所有事物进行归类. 那事物之间存在着相对应的关系. 类与类之间也同样如此. 在面向对象的世界中. 类与类中存在以下关系:
依赖关系,狗和主人的关系
关联关系,你和你的女盆友的关系就是关联关系
组合关系,比聚合还要紧密.比如人的大脑, 心脏, 各个器官. 这些器官组合成一个人. 这时. 人如果挂了. 其他的东西也跟着挂了
聚合关系,电脑的各部件组成完整的电脑,电脑里有CPU, 硬盘, 内存等。 每个组件有自己的生命周期, 电脑挂了. CPU还是好的. 还是完整的个体
继承关系, 类的三大特性之一,子承父业
依赖关系
狗和主人的关系可以理解为是一种依赖关系,如果没有主人,它就是流浪狗了,可能会死。
class Dog:
def __init__(self,name,age,breed,master):
self.name = name
self.age = age
self.breed = breed
self.master = master # master传进来的应该是个对象
self.sayhi() # 调用自己的方法在实例化的时候
def sayhi(self):
print("Hi, I'm %s, a %s dog, my master is %s" %(self.name,self.breed,self.master.name))
class Person:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
def walk_dog(self,dog_obj):
"""遛狗"""
print("主人[%s]带狗[%s]去溜溜。。。" % (self.name,dog_obj.name ))
p = Person("Alex",26,"Male")
d = Dog("Mjj",5,"二哈",p)
p.walk_dog(d)
输出
Hi, I'm Mjj, a 二哈 dog, my master is Alex
主人[Alex]带狗[Mjj]去溜溜。。。
关联关系
你和你女朋友的关系
class Person:
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
self.partner = None # 另一半,是个对象
def do_private_stuff(self):
"""和男/女盆友干点羞羞的事"""
print("%s is doing %s in the 7th hotel." %(self.name,self.partner.name))
p1 = Person("武大郎",25,"男")
p2 = Person("黑姑娘",23,"女")
p1.partner = p2 # 两个对象要互相绑定彼此
p2.partner = p1
p1.do_private_stuff()
p2.do_private_stuff()
以上虽然实现了2个对象的关联,但细想其实是有问题的,武大郎和黑姑娘需要在自己的实例中分别绑定下彼此才能实现伴侣关系。假如有一方忘记了关联,那这个伴侣关系就只是单方面成立了,黑姑娘知道自己的另一伴是武大郎,武大郎却不识黑姑娘。
为了确保这两人的关系是一致的,怎么办呢?
可以创建个单独的类,存储2个人的关系状态,2个人在查自己的感情状态时,都到这个单独的实例里来查
class RelationShip:
"""保存2个人的感情关联关系"""
def __init__(self):
self.couple = []
def make_couple(self,obj1,obj2):
self.couple.append(obj1)
self.couple.append(obj2)
print("[%s] 和 [%s] 正式结为对象..." % (obj1.name,obj2.name))
def break_up(self):
if self.couple:
print("[%s] 和 [%s] 要分手了...真好" % (self.couple[0].name,self.couple[1].name))
self.couple.clear()
else:
print("你根本就没对象,你分手个蛋呀...")
def get_my_partner(self,obj):
"""返回我的另一半"""
for i in self.couple:
if obj != i: # copule列表里有2个值,一个是我自己,一个是我对象,只要跟传进来的obj不相等,代表找到了我对象
return i.name
else:
print("你没有对象,自己心里没有点数么....")
class Person:
def __init__(self,name,age,sex,relation_obj):
self.name = name
self.age = age
self.sex = sex
self.relation = relation_obj # 把RelationShip对象传进来
#self.partner = None # 另一半,是个对象
def do_private_stuff(self):
"""和男/女盆友干点羞羞的事"""
print("%s is doing %s in the 7th hotel." %(self.name,self.relation.get_my_partner(self)))
relation_obj = RelationShip()
p1 = Person("武大郎",25,"男",relation_obj)
p2 = Person("黑姑娘",23,"女",relation_obj)
relation_obj.make_couple(p1,p2) # 把2个人结合在一起
p1.do_private_stuff()
p2.do_private_stuff()
p1.relation.break_up() # 要分手了
p1.relation.get_my_partner(p1) # 再去查,就没有对象了
p2.relation.get_my_partner(p2) # 再去查,就没有对象了
组合关系
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
class Dog: # 定义一个狗类
role = 'dog' # 狗的角色属性都是狗
......
class Weapon:
def stick(self,obj):
"""打狗棒"""
self.name = "打狗棒"
self.attack_val = 40
obj.life_val -= self.attack_val
self.print_log(obj)
def knife(self,obj):
"""屠龙刀"""
self.name = "屠龙刀"
self.attack_val = 80
obj.life_val -= self.attack_val
self.print_log(obj)
def gun(self,obj):
"""AK47"""
self.name = "AK47"
self.attack_val = 100
obj.life_val -= self.attack_val
self.print_log(obj)
def print_log(self,obj):
print("[%s]被[%s]攻击了,掉血[%s],还剩血量[%s]..." %(obj.name,self.name,self.attack_val,obj.life_val))
class Person: # 定义一个人类
role = 'person' # 人的角色属性都是人
def __init__(self, name, sex, attack_val):
self.name = name
self.attack_val = attack_val
self.life_val = 100
self.sex = sex
self.weapon = Weapon() # 在此处实例化一个Weapon对象
def attack(self,dog):
# 人可以攻击狗,这里传递进来的dog也是一个对象。
# 人攻击狗,那么狗的生命值就会根据人的攻击力而下降
dog.life_val -= self.attack_val
print("人[%s]打了狗[%s],狗掉血[%s],还剩血量[%s]..." % (self.name,dog.name,self.attack_val,dog.life_val))
d = Dog("mjj","二哈",20)
p = Person("Alex","Male",60)
d.bite(p) # 对象交互,把p实例传递给d的方法
p.attack(d)
p.weapon.knife(d) # 通过组合的方式调用weapon实例下的具体武器
p.weapon.stick(d)
用组合的方式建立了类与组合的类之间的关系,它是一种‘有’或者”包含”的关系,比如老师有生日,老师教python课程。 你有女朋友,你朋友有自己的一些特征
class BirthDate:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
class Course:
def __init__(self, name, price, period):
self.name = name
self.price = price
self.period = period
class Teacher:
def __init__(self, name, gender, birth, course):
self.name = name
self.gender = gender
self.birth = birth
self.course = course
def teaching(self):
print('teaching.....',self.course.name)
p1 = Teacher('Alex', 'Male',
BirthDate('1995', '1', '27'),
Course('Python', '28000', '5 months')
)
print(p1.birth.year, p1.birth.month, p1.birth.day)
print(p1.course.name, p1.course.price, p1.course.period)
当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好
类变量的用途
我们知道类变量是存在类里,实例变量存在每个实例里,那什么时候用类变量呢?
例子:我要把中国14亿人的都分别生成一个实例。
class Person:
nationality = "Chinese"
def __init__(self,name,sex,birthday,hometown):
self.name = name
self.sex = sex
self.birthday = birthday
self.hometown = hometown
p1 = Person("Alex","Male","1995-05-32","山东德州")
p2 = Person("Mjj","Ladyboy","1992-06-16","河南信阳")
print(p1.nationality,p2.nationality)
输出结果:
Chinese Chinese
由于中国人的国籍都是Chinese, 此时你没必要存14亿份这个数据,存一份就好。
可如果有人改国籍怎么办?
p2.nationality = "Japan" # 这个动作相当于把p2.nationality变成了实例变量
print(p1.nationality,p2.nationality)
输出:
Chinese Japan # 并不会影响p1的国籍
属性的增删改查
class Person:
nationality = "Chinese"
addr = "北京"
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
# 实例属性操作
p = Person("Alex",26,"Male")
p.name = "Alex Li 金角大王" # 修改属性
p.job = "CEO" # 添加实例属性
del p.sex # 删除实例属性
print(p.job) #打印添加的实例属性
# 类属性操作
Person.nationality = "US"
Person.race = "Yellow" # 添加类属性
del Person.addr
print(p.addr) # 再调用已删除的类属性就会报错了
练习题
开发一个反恐游戏,有警察、恐怖分子,还有各种武器,他们可以互砍互杀。
注意,警察不能用炸药包,恐怖分子可以。炸药包一用,全部玩家都得死。
提示:可以只写一个Person类,一个weapon类。