类与类之间的关系:
- 继承
- 关联(包括:组合,聚合)
- 依赖
( 这里别和 面向对象的三大特性 搞混了 ===> 继承、封装、多态 )
多态:多种形态
关联:一个类的对象作为另一个类的 属性
依赖: 一个类的对象作为另一个类的 方法的参数
三种关系之间的耦合程度:继承 > 关联(聚合 > 组合)> 依赖
开发项目时的一个原则是:高内聚,低耦合
1. 继承关系
class animal():
def eat(self):
print("吃饭")
class person(animal):
def eat(self):
print("吃大米饭")
class dog(animal):
def eat(self):
print("吃骨头")
class cat(animal):
def eat(self):
print("吃鱼")
p = person()
d = dog()
c = cat()
p.eat()
d.eat()
c.eat()
person( ) 、cat( ) 、dog( ) 与 animal( ) 之间都是继承关系
创建的都是 不同子类的对象,创建完对象后调用的都是 相同的方法,但是打印出的结果是不同的,这就是 多态
多态 就是多种形态,
多态得有 依赖,多态得有 继承,因为没有继承,就没有重写,没有重写就没有多态
2. 关联关系
class student():
def __init__(self,name): # 构 造 函 数 ,name属性
self.name = name # 构 造 函 数 进 行 一 个 属 性 赋 值
def study(self):
print("我爱python")
class teacher():
def __init__(self,stu): # 构 造 函 数 里 加 一 个 stu 参 数
self.stu = stu # 下 面 传 过 来 的 学 生 对 象 stu 进 行 赋 值
def teach(self): # 创 建 一 个 teach 对 象
print("教%spython"%self.stu.name)
|------> 教 学 生 对 象 里 的 name 属 性 !
s = student("范高伦") # student 需 要 一 个 字 符 串 名 字 ,,学 生 对 象 赋 给 s
t = teacher(s) # s 传 到 这 ,传 到 上 面 teacher 对 象 的 stu,
t.teach() # 调 teach 方 法
一个类的对象作为另一个类的属性,这样的关系就是 关联关系 (两者之间有一点包含关系)
如上面案例,学生student类 作为 stu属性
关联 里还分 组合 和 聚合,看这两个类的生命周期,看它俩的关联程度
- 两者关系比较紧密,谁离开谁活不了,那叫 聚合;
把 “身体” 作为一个类,把 “头”、“四肢” 分别定义一个类,身体里可以包含这三者,身体 和 头 属于 聚合关系(关系比较紧密) - 身体和四肢 就是 组合关系(关系没那么同生共死)
3.依赖关系
class student():
def __init__(self,name):
self.name = name
def study(self):
print(" 我爱python ")
class teacher():
def teach(self,stu):
print(" 教%spython "%stu.name)
s = student("范高伦")
t = teacher()
t.teach(s)
一个类的对象 作为另一个类中 方法的参数,这时候不是 属性 了,这样的关系叫 依赖关系
水杯 和 杯盖 之间是 关联关系,因为 水杯包含杯盖
我拿水杯 ,我和水杯之间,我拿水杯应该是我的一个行为,是 “ 我 ” 这个类里的一个方法,这时水杯和我之间是 依赖关系
4. 方法、属性
方法 分为 类方法 和 对象方法;
属性也分为 类属性 和 对象属性;
class A():
name = "张三" #类属性
def __init__(self,age):
self.age = age # 对象属性
@staticmethod
def a():
print("类方法中的静态方法")
def aa(self):
print("对象方法")
print(A.name)
A.a()
a = A(18)
print(a.age) # age 对 象 属 性
a.aa()
5. 封装
优点:代码复用(一次写好重复利用)/ 减少代码冗余 / 能够把属性进行一次归类,提高代码可读性
缺点:这三个都存在耦合度,缺点不是绝对的缺点,视情况而定
class A():
def a(self,name):
print(name)
class B(A):
def a(self):
print("子类a方法")
b = B()
‘’‘
class A():
__name = "张三" # 前面加两下划线表示封装,在外面就用不了。name属于类属性 _A__name;注意!:一个下划线达不到封装效果,标标准准两个
def __init__(self,age): # slef._A__age
self.__age = age # 对象属性
@staticmethod
def __a(): # _A__a()
print("类方法-静态方法",A.__name__)
def __aa(self): # slef._A__aa()
print("对象方法")
print(A.name)
正常访问应该是这样:结果报错 : 没有属性 __a
_A__name的形式:
封装的目的是为了安全,只有在类体里的属性才可以用,出了类体就用不了了,name属性在A类里可以用
def get_age(self):
return self.__age
def set_age(self,age):
if age>150 or age<0:
print("非法年龄")
else:
self.__age = age
@staticmethod
def get_name():
return A.__name
@staticmethod
def set_name(name):
if isinstance(name,str):
A.__name = name
else:
raise TypeError(" 类 型 错 误 ,非 str 类 型 不 能 赋 值 ")
A.set_name("asdf")
print(A.get_name())
'''
class A():
def __init__(self,name):
self.name = name
def a(self):
print("我是a")
def _b(self):
print("我是_b")
def __c(self):
print("我是__c")
def __eq__(self, other):
return self.name==other.name
# print(dir(object))
# a = A()
# print(isinstance(a,object))
# print(issubclass(B,A))
# a1 = A("zs")
# a2 = A("zs1")
# print(a1.__eq__(a2))
# print()