在一个项目中,我在使用继承的时候陷入了设计中。现在我试着摆脱它,转而使用合成,因为这似乎是解决我问题的合适方法。然而,我需要多愁善感,我不确定我是否以正确的方式实现了我的作品。在
有人能看看我下面的代码吗?在最后三行中,我希望所有的动物都能行走,但前提是它们有行走的能力。在调用这个属性的函数之前,先检查一个对象是否具有某个属性(在本例中为“legs”),这是一个好的做法吗?我只是想知道这是一个正确的方法,还是有更好的方法。在
class Animal:
def __init__(self, name):
self.name = name
def make_sound(self):
print("silence...")
class Wings:
def flap(self):
print("Wings are flapping")
class Legs:
def walk(self):
print("Legs are walking")
class Bird:
def __init__(self):
self.animal = Animal("Bird")
self.wings = Wings()
def make_sound(self):
print(f"{self.animal.name} is Singing!")
class Dog:
def __init__(self):
self.animal = Animal("Dog")
self.legs = Legs()
def make_sound(self):
print(f"{self.animal.name} is Barking")
class Cat:
def __init__(self):
self.animal = Animal("Cat")
self.legs = Legs()
def make_sound(self):
print(f"{self.animal.name} is Meowing!")
if __name__ == '__main__':
animals = list()
animals.append(Bird())
animals.append(Dog())
animals.append(Cat())
for animal in animals:
animal.make_sound()
for animal in animals:
if hasattr(animal, 'legs'):
animal.legs.walk()
你已经有点过头了
继承描述“是”关系,组合描述“有”关系。因此,在您的例子中,使用组合来处理像翅膀和腿这样的属性是非常合理的,但是鸟、猫和狗都是动物-它们没有动物(嗯,它们都有跳蚤,但这是另一个主题)-所以它们应该继承自
Animal
。在而且,大多数鸟的腿太粗了,还有相当一部分根本就不会飞(但有些鸟用腿游泳,而且游得很有效率);—)
要看具体情况。一般来说,不,这不被认为是好的做法(参见“告诉-不要问”和“德米特法则”),但在某些情况下它是合法的。而且,“好”的设计也取决于要解决的问题,我们这里达到了玩具示例的极限,这些示例永远不能代表真实的用例。在
理论上,组合/委托对客户机代码应该是透明的,所以您应该只调用
whatever_animal.walk()
并完成它。现在你(作为“客户端代码”)可能想知道动物不能行走,在这种情况下,非行走的动物应该提出一个例外,当收费步行。。。它还意味着Animal
必须为所有可能的“actions”提供一个默认实现,并且客户机代码必须为“UnsupportedAction”(或者您想如何命名它们)异常做好准备。在wrt/implementation,使委托透明可以像使用
__getattr__()
一样简单,即:这个解决方案的优点是它非常简单而且非常动态。不太好的一点是它既不可检查也不明确。在
另一种解决方案是明确授权:
^{pr2}$这是相当冗长,更不动态,但许多移动明显,记录,可读和检查。在
在上面的示例中,您实际上可以使用自定义描述符来分解冗余代码:
但是,再一次,如果没有一个真正的问题需要解决,那么这些都是没有意义的,因为这个问题通常定义了正确的解决方案。在
相关问题 更多 >
编程相关推荐