Python面向对象之组合

发布时间 2024-01-12 20:34:01作者: Lea4ning

组合

【一】什么是组合

  • 组合是通过将不同的类或模块组合在一起,创建一个新的类来实现的机制。这意味着一个类的对象可以包含其他类的对象作为其部分,通过组合这些部分来实现整体的功能。

【二】组合与继承的区别

  • 继承(Inheritance)和组合(Composition)是两种不同的代码复用机制,它们在面向对象编程中有着不同的实现和影响。
    1. 继承(Inheritance):
      • 定义: 继承是通过创建新类,基于现有类的属性和方法来构建的机制。子类继承了父类的特性,可以使用父类的属性和方法,并且可以在子类中添加、修改或扩展这些特性。
      • 关系: 继承通常表示 "is-a" 关系,即子类是父类的一种类型。例如,如果有一个Vehicle类,那么CarBicycle等子类可以继承自Vehicle,因为它们都是交通工具。
    2. 组合(Composition):
      • 定义: 组合是通过将不同的类或模块组合在一起,创建一个新的类来实现的机制。这意味着一个类的对象可以包含其他类的对象作为其部分,通过组合这些部分来实现整体的功能。
      • 关系: 组合通常表示 "has-a" 关系,即一个对象包含另一个对象。例如,一个Car对象可能包含一个引擎(Engine)对象、轮胎(Tire)对象等,通过组合这些对象,实现了汽车的功能。
  • 区别:
    • 代码复用: 继承可以在子类中重用父类的代码,但有时可能导致过度耦合和继承链的问题。组合通过将不同的模块组合在一起,提供了更灵活的代码复用机制,减少了耦合。
    • 关系: 继承建立了 "is-a" 关系,表示子类是父类的一种类型。组合建立了 "has-a" 关系,表示一个对象包含另一个对象。

【三】代码解释

【1】交通工具

class Vehicle():
    def __init__(self, color, speed, tyre_num):
        # 交通工具都有的属性【并不严谨奥,只是演示】
        self.color = color  # 颜色
        self.speed = speed  # 时速
        self.tyre_num = tyre_num  # 轮胎数量


class Tyre():  # 轮胎
    def __init__(self, size, price):
        self.size = size
        self.price = price

        
'''根据轮胎实例化出来两个轮胎对象'''
car_tyre = Tyre('24inch', 2000)  # 汽车轮胎参数
bicycle_tyre = Tyre('28inch', 300)  # 自行车轮胎参数


class Car(Vehicle):
    # 汽车是【is】交通工具
    def __init__(self, color, speed, tyre_num, consume):
        # 汽车继承交通工具所需要的参数
        super().__init__(color, speed, tyre_num)
        self.consume = consume  # 消耗的东西
        self.tyre = car_tyre   # 汽车有【has】汽车轮胎
        '''同样,可以直接实例化对象'''
        # self.tyre = Tyre('24inch', 2000)


class Bicycle(Vehicle):
    # 自行车是【is】交通工具
    def __init__(self, color, speed, tyre_num, consume):
        # 自行车继承交通工具所需要的参数
        super().__init__(color, speed, tyre_num)
        self.consume = consume  # 消耗的东西
        self.tyre = bicycle_tyre   # 自行车有【has】自行车轮胎
        '''同样,可以直接实例化对象'''
        # self.tyre = Tyre('28inch', 300)


car = Car('red', '120km/h', 4, 'oil')
bicycle = Bicycle('yellow', '60km/h', 2, 'manpower')
print(car.__dict__)
# {'color': 'red', 'speed': '120km/h', 'tyre_num': 4, 'consume': 'oil', 'tyre': <__main__.Tyre object at 0x00000214913D3FD0>}
print(bicycle.__dict__)
# {'color': 'yellow', 'speed': '60km/h', 'tyre_num': 2, 'consume': 'manpower', 'tyre': <__main__.Tyre object at 0x00000214913D3E80>}

print(car.tyre.price)  # 2000   # 可以拿到汽车轮胎的具体参数
print(bicycle.tyre.price)  # 300   # 可以拿到自行车轮胎的具体参数
  • 轮胎与自行车/汽车 就相当于组合了

【2】学校信息系统

class Course:
    def __init__(self, name, period, price):
        self.name = name
        self.period = period
        self.price = price

    def __str__(self):
        return f"""
        课程名称:{self.name}
        课程周期:{self.period}
        课程价格:{self.price}
        """


class School:
    school = "OldBoy"
    address = 'SH'


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


python = Course('python', '6mon', 10000)
linux = Course('linux', '3mon', 20000)

# Teacher类基于继承来重用Person的代码
# 基于组合来重用Course类的代码
class Teacher(Person):
    def __init__(self, name, age, course=None):
        super().__init__(name, age)
        self.course = course


class Student(Person):
    def __init__(self, name, age, class_num):
        super().__init__(name, age)
        self.class_num = class_num


class Admin(Person):
    def __init__(self, name, age, level):
        super().__init__(name, age)
        self.level = level


stu1 = Student('user001', 15, '1-1')
stu2 = Student('user002', 14, '1-2')

# 将python对象作为course参数传入
tea1 = Teacher('tea001', 28, [python])
tea2 = Teacher('tea002', 23, [python, linux])
print(tea1.__dict__)   # {'name': 'tea001', 'age': 28, 'course': [<__main__.Course object at 0x00000216CB087FD0>]}
print(tea2.__dict__)   # {'name': 'tea002', 'age': 23, 'course': [<__main__.Course object at 0x00000216CB087FD0>, <__main__.Course object at 0x00000216CB087D60>]}

for i in tea1.course:
    print('tea1')
    print(i)
for i2 in tea2.course:
    print('tea2')
    print(i2)

【2】流浪图书管理系统

  • 其中没有显式的使用组合,但是我觉得很巧妙
class Book:

    def __init__(self, name, author, comment, state=0):
        self.name = name
        self.author = author
        self.comment = comment
        self.state = state

    def __str__(self):
        status = '未借出'
        if self.state == 1:
            status = '已借出'
        return '名称:《%s》 作者:%s 推荐语:%s\n状态:%s ' % (self.name, self.author, self.comment, status)


class BookManager:
    books = []

    def __init__(self):
        book1 = Book('惶然录', '费尔南多·佩索阿',
                     '一个迷失方向且濒于崩溃的灵魂的自我启示,一首对默默无闻、失败、智慧、困难和沉默的赞美诗。')
        book2 = Book('以箭为翅', '简媜',
                     '调和空灵文风与禅宗境界,刻画人间之缘起缘灭。像一条柔韧的绳子,情这个字,不知勒痛多少人的心肉。')
        book3 = Book('心是孤独的猎手', '卡森·麦卡勒斯',
                     '我们渴望倾诉,却从未倾听。女孩、黑人、哑巴、醉鬼、鳏夫的孤独形态各异,却从未退场。', 1)
        self.books.append(book1)
        self.books.append(book2)
        self.books.append(book3)

    def menu(self):
        print(
            '欢迎使用流浪图书管理系统,每本沉默的好书都是一座流浪的岛屿,希望你有缘发现并着陆,为精神家园找到一片栖息地。\n')
        while True:
            print('1.查询所有书籍\n2.添加书籍\n3.借阅书籍\n4.归还书籍\n5.退出系统\n')
            choice = int(input('请输入数字选择对应的功能:'))
            if choice == 1:
                self.show_all_book()
            elif choice == 2:
                self.add_book()
            elif choice == 3:
                self.lend_book()
            elif choice == 4:
                self.return_book()
            else:
                print('感谢使用!愿你我成为爱书之人,在茫茫书海里相遇。')
                break

    def show_all_book(self):
        print('书籍信息如下:')
        for book in self.books:
            print(book)
            print('')

    def add_book(self):
        new_name = input('请输入书籍名称:')
        new_author = input('请输入作者名称:')
        new_comment = input('请输入书籍推荐语:')
        new_book = Book(new_name, new_author, new_comment)
        self.books.append(new_book)
        print('书籍录入成功!\n')

    def check_book(self, name):
        for book in self.books:
            if book.name == name:
                return book
        else:
            return None

    def lend_book(self):
        name = input('请输入书籍的名称:')
        res = self.check_book(name)

        if res != None:
            if res.state == 1:
                print('你来晚了一步,这本书已经被借走了噢')
            else:
                print('借阅成功,借了不看会变胖噢~')
                res.state = 1
        else:
            print('这本书暂时没有收录在系统里呢')

    def return_book(self):
        name = input('请输入归还书籍的名称:')
        res = self.check_book(name)
        if res == None:
            print('没有这本书噢,你恐怕输错了书名~')
        else:
            if res.state == 0:
                print('这本书没有被借走,在等待有缘人的垂青呢!')
            else:
                print('归还成功!')
                res.state = 0


manager = BookManager()
manager.menu()