面向对象之派生和组合

面向对象之派生和组合

派生

  • 派生是指,子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法

一、派生的方法

  • 子类是必须要派生出自己的数据属性不然就无数据属性可用
  • 子类无法使用父类中__init__定义的属性
class Person(object):
    def __init__(self, name, age):
        self.name = name


class Teacher(Person):
    def __init__(self, name):
        self.name = name

    def get_name(self):
        print(f'老师的名字是{self.name}')


teacher_1 = Teacher('Xanadu')
teacher_1.get_name()  # 名字是Xanadu
  • 那怎么样可以使用继承的父类中__init__定义的属性呢?有以下两种方法

[1]指名道姓的调用__init__方法

class Person(object):

    def __init__(self, name):
        self.name = name


class Teacher(Person):
    def __init__(self, name):
        #指名道姓的使用父类中的__init__方法
        Person.__init__(self, name)
        self.name = name

    def get_name(self):
        print(f'老师的名字是{self.name}')


teacher_1 = Teacher('Xanadu')
teacher_1.get_name()  # 老师的名字是Xanadu

[2]超类(super()

  • 调用super()会得到一个特殊的对象
  • 该对象专门用来引用父类的属性
  • 且严格按照MRO规定的顺序向后查找
class Person(object):

    def __init__(self, name):
        self.name = name


class Teacher(Person):
    def __init__(self, name):
        super().__init__(name)
        self.name = name

    def get_name(self):
        print(f'老师的名字是{self.name}')


teacher_1 = Teacher('Xanadu')
teacher_1.get_name()  # 老师的名字是Xanadu
  • 提示:在Python2中super的使用需要完整地写成super(自己的类名,self) ,而在python3中可以简写为super()
  • 当你使用super()函数时,Python会在MRO列表上继续搜索下一个类
  • 只要每个重定义的方法统一使用super()并只调用它一次,那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次
  • 使用super调用的所有属性,都是从MRO列表当前的位置往后找,千万不要通过看代码去找继承关系,一定要看MRO列表

[3]小结

  • 这两种方式的区别是:
    • 方式一是跟继承没有关系的,而方式二的super()是依赖于继承的
    • 并且即使没有直接继承关系,super()仍然会按照MRO继续往后查找

组合

  • 在一个类中以另外一个类的对象作为数据属性,称为类的组合。

一、组合的使用

  • 组合与继承都是用来解决代码的重用性问题。
  • 不同的是:
    • 继承是一种“是”的关系,比如老师是人、学生是人,当类之间有很多相同的之处,应该使用继承;
    • 而组合则是一种“有”的关系,比如工资有税,有交税的等级,老师有税前工资和税后工资,当类之间有显著不同,并且较小的类是较大的类所需要的组件时,应该使用组合
class Level(object):
    def __init__(self, days, posts):
        self.days = days
        self.posts = posts
        self.daily = Daily(posts)

    def get_level(self):
        if int(self.days) * self.daily.get_daily() > 10000:
            return 0.2
        else:
            return 0.1


class Daily(object):
    def __init__(self, posts):
        self.posts = posts

    def get_daily(self):
        if self.posts == '普通职员':
            return 300
        else:
            return 500


class Tax(object):
    def __init__(self, days, posts):
        self.days = days
        self.daily = Daily(posts)
        self.level = Level(days, posts)

    def get_tax(self):
        return int(self.days) * self.daily.get_daily() * self.level.get_level()


class Wages(object):
    def __init__(self, days, posts):
        self.days = days
        self.posts = posts
        #工资有交税的等级
        self.level = Level(days, posts)
        # 工资有日薪
        self.daily = Daily(posts)
        # 工资有税
        self.tax = Tax(days, posts)

    def wages(self):
        days = int(self.days)
        print(f'税前工资是{days * self.daily.get_daily()}')

    def true_wages(self):
        days = int(self.days)
        print(f'税后工资是{days * self.daily.get_daily() - self.tax.get_tax()}')


my_wages = Wages(30, '普通职员')
my_wages.wages()  # 税前工资是9000
my_wages.true_wages()  # 税后工资是8100.0
my_wages_1 = Wages(30, '经理')
my_wages_1.wages()  # 税前工资是15000
my_wages_1.true_wages()  # 税后工资是12000.0
  • 此时对象my_wages集对象独有的属性、Wages类中的内容、Tax类中的内容于一身(都可以访问到),是一个高度整合的产物
  • 当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好

二、组合和继承的区别

  • 组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同,

[1]继承的方式

  • 通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。
  • 当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人

[2]组合的方式

  • 用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...
posted @ 2024-01-29 14:46  桃源氏  阅读(41)  评论(0)    收藏  举报