【问题标题】:How to add same methods/properties to a set of subclasses derived from common class如何将相同的方法/属性添加到从公共类派生的一组子类中
【发布时间】:2012-06-20 15:28:13
【问题描述】:

向从同一类派生的子类添加一组通用方法/属性的正确方法是什么?

假设这些是我制作基于动物的视频游戏所需的课程(这只是一个例子,我并不是真的在写游戏,但想法是一样的)

class Animal():
    def __init(self, numlegs):
        self.numlegs = numlegs

class Dog(Animal):
    def __init(self, numlegs):
        Animal.__init__(self, numlegs)

    def bark(self):
        print "Arf!"

class Cat(Animal):
    def __init(self, numlegs):
        Animal.__init__(self, numlegs)

    def playwithmouse(self):
        print "It's fun!"

class Duck(Animal):
    def __init(self, numlegs):
        Animal.__init__(self, numlegs)

    def fly(self):
        print "Weee!"

在游戏中的某个特定时刻 Dog 和 Duck 可以武器化,它们需要具有相同的方法:fire()、reload() 和属性:ammocount。

我认为将它们添加到 Animal() 类中是不正确的,因为游戏中完全不同的部分将需要它们。

添加它们的正确方法是什么?

更新 我想补充一点,预期的结果是某种 动物 - 武器混合类如

class BurtalDuck(Duck):
    fire(): #<- this is somehow added to Duck
        print "ratatatatat!"

我从答案中得到的是,如果我需要整套“武器/弹药”,我可以使用多职业,否则组合就是要走的路。

【问题讨论】:

  • 不,这不是家庭作业,谢谢你的提问 =)
  • +1 武器化鸭子的想法。
  • 我不知道什么是mixin,现在查一下。
  • @DSM(如果你得到参考,+1),这就是为什么我去任何地方都没有我的猎鸭炭疽病。

标签: python class subclass


【解决方案1】:

您可以在 python 中利用多重继承,如下所示:

class Weapon():
    def __init__(self):
        self.ammoCount = 0
    def fire():
        print "fire!"
    def reload():
        print "reloading!"

class Dog(Animal, Weapon):
    def __init(self, numlegs):
        Animal.__init__(numlegs)

    def bark(self):
        print "Arf!"

现在你可以这样做了:

dog = Dog(4)
dog.fire()

如果Dog应该成为Animal,而不是Animal-Weapon-hybrid,则使用实例Weapon 并将其作为组件分配给狗:

class Dog(Animal, Weapon):
    def __init(self, numlegs):
        Animal.__init__(numlegs)
        self.weapon = Weapon()

    def bark(self):
        print "Arf!"

那么你必须使用dog.weapon.fire()。这可能不符合您对Dog实际上武器的概念,但它现在已被武器化。 :)

如果你有一个狗实例并且你需要它在飞行中被武器化,只需利用 python 的动态属性分配

class Dog(Animal):
    def __init(self, numlegs):
        Animal.__init__(numlegs)

    def bark(self):
        print "Arf!"
#some other code maybe
dog = Dog(4)
#more other code
dog.weapon = Weapon()
#even more code
dog.weapon.fire()

一般我会说:

  • 如果您希望DogDuck 成为武器,请使用继承。
  • 如果您希望 DogDuck 包含拥有一种(或多种)武器,请使用组件。

【讨论】:

  • 好的,再次编辑评论,我想只保留 Dog 类作为 Animal 的子类,并且只在我的代码的另一部分将它们武器化(想象一下我想要的游戏版本 2使用相同的类而不修改它们)
  • 我建议改用接口,但据我所知,python 不支持 :)
  • 感谢您扩展您的答案,此外,阅读 Mark Hildreth 的关于 SO 关于继承 VS 组合的问题的链接,让一切变得更加清晰。
  • 我很高兴能帮上忙。 :) 使用组合而不是继承对于解耦特别有用,并且经常用于实现design patterns。我肯定会仔细看看。
【解决方案2】:

一种可能性:根本不要将它们添加到类中。创建一个“武器”类,其中包含有关武器如何工作的所有信息,并将该类的一个实例添加到可能是武器的对象中。

当然,这意味着要重新考虑您的架构,但这是一个值得思考的好概念。这个想法通常被称为“基于组件”。 Google for "component-based game objects" 并尝试找到一些描述该想法的博客文章/演示文稿。

【讨论】:

  • “添加实例”是指将其分配给类中的某个变量?看起来不是很 oop(但我该说什么是 oop 呢?=)
  • 这归结为继承(你想要完成的事情)和组合(我的建议)之间的决定。它们各有优缺点,使用它们的人也有一些偏见。以下问题提供了更多信息来确定什么是好方法:stackoverflow.com/questions/49002/…
【解决方案3】:

用合成来做这个,

class Weapon(object):
    def __init__(self, type):
        self.type = type

class Dog(Animal):
    def __init(self, numlegs):
        Animal.__init__(numlegs)
        self.gun = Weapon("gun")

    def bark(self):
        print "Arf!"

【讨论】:

    【解决方案4】:

    另一种方法,使用 mixins:

    class Animal(object):
        def __init__(self, n):
            super(Animal,self).__init__()
            if isinstance(n, Animal):  # copy constructor
                self.numlegs = n.numlegs
            else:
                self.numlegs = n
        def do(self):
            pass
    
    class Dog(Animal):
        def do(self):
            print "Arf!"
    
    class Cat(Animal):
        def do(self):
            print "Torturing small animals is fun!"
    
    class Duck(Animal):
        def do(self):
            print "Wheee!"
    
    class Weapon(object):
        def __init__(self):
            super(Weapon,self).__init__()
            self.ammocount = 7
    
        def fire(self):
            if self.ammocount > 0:
                print "Bang!"
                self.ammocount -= 1
            else:
                print "<click>"
    
        def reload(self):
            self.ammocount = 7
    
    class WeaponizedDog(Dog, Weapon): pass
    class WeaponizedCat(Cat, Weapon): pass
    class WeaponizedDuck(Duck, Weapon): pass
    
    max = Dog(4)                # max is a 4-legged dog
    max.do()                    # "Arf!"
    max = WeaponizedDog(max)    # If I put my hands in my pockets, I'd be carrying concealed deadly weapons...
    max.fire()                  # "Bang!"
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-25
      • 1970-01-01
      • 1970-01-01
      • 2013-06-03
      • 2014-12-01
      • 2010-11-01
      • 1970-01-01
      相关资源
      最近更新 更多