Python面向对象编程(Object Oriented Programming,OOP)之抽象类(Abstract Class)、类组合(Class Combination)

抽象类

与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化。

抽象类的由来

 如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性。

比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类。你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子...,因为你永远无法吃到一个叫做水果的东西。

从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的。

抽象类与普通类的区别:

  • 抽象类中有抽象方法,该类不能被实例化,只能被继承。
  • 子类必须实现抽象方法(这一点与接口有点类似,但其实是不同的)。

抽象类与接口类

抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计 

在python中,严格来说并没有接口类这种东西,我们是通过专门的模块定义接口来模拟接口的。

1. 多继承问题

  1. 在继承抽象类的过程中,我们应该尽量避免多继承;
  2. 而在继承接口的时候,我们反而鼓励你来多继承接口。
  3. 接口隔离原则:使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口。

2. 方法的实现

在抽象类中,我们可以对一些抽象方法做出基础实现,而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现。

组合

在一个类中以另外一个类的对象作为数据属性。这是软件重用的重要组成方式。

class Weapon:
    def __init__(self, name, att):
        self.name = name
        self.att = att

    def aux_attack(self, p, p1):
        p1.hp -= self.att
        print("%s利用%s攻击了%s%s滴血,%s还剩下%s的血量!" % (p.name, self.name, p1.name, self.att, p1.name, p1.hp))


p1 = Person("小明", "不详", 500, 50)
p2 = Person("小红", "女", 300, 100)

w1 = Weapon("十字镐", 20)
w2 = Weapon("大宝剑", 30)
w3 = Weapon("方天画戟", 50)

p1.attack(p2)  # p1攻击p2,p2还剩300 - 50 = 250血量
w1.aux_attack(p1, p2)  # p1使用w1武器攻击p2,掉20血,剩下230血

p2.attack(p1)  # p2攻击p1,p2还剩500 - 100 = 400血量
w3.aux_attack(p2, p1)  # p1使用w1武器攻击p2,掉50血,剩下350血

结果:

小明攻击了小红,小红还剩下250的血量!
小明利用十字镐攻击了小红20滴血,小红还剩下230的血量!
小红攻击了小明,小明还剩下400的血量!
小红利用方天画戟攻击了小明50滴血,小明还剩下350的血量!

Process finished with exit code 0

上述就是一个组合的经典例子。我们接下来再看一个例题:

圆环是由两个圆组成的,圆环的面积是外面圆的面积减去内部圆的面积。圆环的周长是内部圆的周长加上外部圆的周长。

from math import pi


class Circle:
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return pi * self.radius * self.radius

    def perimeter(self):
        return 2 * pi * self.radius


class Ring:
    def __init__(self, radius1, radius2):
        self.circle1 = Circle(radius1)
        self.circle2 = Circle(radius2)

    def area(self):
        return abs(self.circle1.area() - self.circle2.area())

    def perimeter(self):
        return self.circle1.perimeter() + self.circle2.perimeter()


ring = Ring(5, 8)
print(ring.perimeter())
print(ring.area())

结果:

81.68140899333463
122.52211349000193

Process finished with exit code 0

用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python课程:

class Birthday:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day


class Courses:
    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 teach(self):
        print("{}老师出生于{}年{}月{}日,性别为{},教授{}{}时间,选课需要花费{}元。".format(
            self.name, self.birth.year, self.birth.month, self.birth.day,
            self.gender, self.course.name, self.course.period,
            self.course.price))


t1 = Teacher("张三", "男", Birthday("1995", "12", "20"), Courses("python", "10000", "5个月"))
t1.teach()

结果:

张三老师出生于1995年12月20日,性别为男,教授python5个月时间,选课需要花费10000元。

Process finished with exit code 0

当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好。


猜你喜欢

转载自blog.csdn.net/qq_33567641/article/details/81225576