python 中构图的实际用法

a realistic usage of composition in python

我一直在阅读 python 中的作文,在关注了 stackoverlow 上的一些文章和答案之后,我想我能够得到 what 是,如何 实现。但我无法找到答案的一个问题是 为什么 组合? (不与继承的好处进行比较)。这是我从 here:

得到的一个例子
class Salary:
    def __init__(self,pay):
        self.pay=pay

    def get_total(self):
       return (self.pay*12)

class Employee:
    def __init__(self,pay,bonus):
        self.pay=pay
        self.bonus=bonus
        self.obj_salary=Salary(self.pay)

    def annual_salary(self):
        return "Total: "  +  str(self.obj_salary.get_total()+self.bonus)


obj_emp=Employee(100,10)
print (obj_emp.annual_salary())

我想通过一个实际的例子来理解,将两个相关的东西分开会有好处 类( 到底有什么好处?)

使用示例的扩展版本

class Salary:
    def __init__(self,pay):
        self.pay=pay

    def get_total(self):
       return (self.pay*12)

    def increase(self):
        self.pay *= 1.1


class Employee:
    def __init__(self,pay,bonus):
        self.pay=pay
        self.bonus=bonus
        self.obj_salary=Salary(self.pay)

    def annual_salary(self):
        return "Total: "  +  str(self.obj_salary.get_total()+self.bonus)


obj_emp=Employee(100,10)
print (obj_emp.annual_salary())

调用 employee.salary.increase 比 employee.increase

更有意义

另外,如果您需要多个对象怎么办?您会继承其中之一还是全部导致名称可能的名称冲突?

class Game:
    def __init__(self):
        self.screens       = [LoadingScreen, MapScreen]        
        self.player        = Player()
        self.display       = Display()
        self.stats         = Stats(self.display)
        self.screenIndex   = self.player.getScreen()
        self.currentScreen = self.screens[self.screenIndex]()
        self.run()

* 编辑 * 看完这个

but on looking it up again i find that increase could be renamed to increaseSalary so employee.increaseSalary() would make sense right?

您可以简单地将增加额转移给员工 class 但是如果您有经理 class 或老板 class 怎么办,您将需要为每个人重复相同的代码 class

class Employee:
    def __init__(self,pay,bonus):
        self.pay=pay
        self.bonus=bonus

    def annual_salary(self):
        return "Total: "  +  str(self.obj_salary.get_total()+self.bonus)

    def increase_salary(self):
        self.pay *= 1.1


class Manager:
    def __init__(self,pay,bonus):
        self.pay=pay
        self.bonus=bonus

    def annual_salary(self):
        return "Total: "  +  str(self.obj_salary.get_total()+self.bonus)

    def increase_salary(self):
        self.pay *= 1.1

class Boss:
    def __init__(self,pay,bonus):
        self.pay=pay
        self.bonus=bonus

    def annual_salary(self):
        return "Total: "  +  str(self.obj_salary.get_total()+self.bonus)

    def increase_salary(self):
        self.pay *= 1.1

仅一次

class Salary:
    def __init__(self,pay):
        self.pay=pay

    def get_total(self):
       return (self.pay*12)

    def increase(self, addition):
        self.pay *= addition

您还可以使用 class 方法更轻松地找到平均值、最大值、最小值等

好的,我会尝试一下,尽管我有点菜鸟。也可能有一些我遗漏的要点,但这是我喜欢思考的方式,任何人,答案:

因为它为您提供了很大的灵活性,并允许您将不一定具有 parent/child 关系的对象 'compose' 在一起(在 classical OOP 中称为IS-A 类型继承)

例如,假设您有一个 rifleclass。你想在上面添加(或编写)attachments

你会如何处理继承?它不会很灵活。

所以你可以做的是定义你的附件,因为它们有 classes,比如 sightmuzzle break class,然后声明这些的实例附件 classes 作为 rifle class 和 BAM 中的字段 您现在可以访问 sightmuzzle break 中定义的方法,就像继承 a child class 可以访问它的 superclasses 方法。

无论如何继续,你可以从这个例子中看到现在创建各种武器 class 是多么容易,比如 howitzer,如果做得好你可以声明实例sightmuzzle breakhowitzer.

请注意,我们创建的关系层次结构是完全扁平的。

要通过继承完成所有这些操作,您可以定义一个基础 class,例如 weapon,并使用 sightmuzzle break 中定义的相同方法。然后你会创建分支到 riflehowitzer.

的子 classes

现在假设您不希望 rifle 有一个 sight,而是 scope。你必须在你的基地经历所有这些箍和恶作剧 class 才能实现这一目标。

使用组合,您只需创建一个新的 class scope(实际上可以从 sight 继承),从 [=] 中删除 sight 的实例10=] 并插入 scope 的字段实例。请注意,howitzer.

没有任何变化

尽管如此,我仍然认为继承是一种在适当情况下可以利用的有用工具,就像组合一样。