我一直在学习如何在python编程中实现组合,但我很难理解为什么它比继承更受欢迎。
例如,到目前为止,以下是我的代码:
class Particle:
# Constructor (public)
def __init__(self, _name, _charge, _rest_energy, _mass, _velocity):
# Attributes (private)
self.__name = _name
self.__charge = _charge
self.__restEnergy = _rest_energy
self.__mass = _mass
self.__velocity = _velocity
# Getter functions (public)
def getName(self):
return self.__name
def getCharge(self):
return self.__charge
def getRestEnergy(self):
return self.__restEnergy
def getMass(self):
return self.__mass
def getVelocity(self):
return self.__velocity
# Setter procedures (public)
def setName(self, _name):
self.__name = _name
def setCharge(self, _charge):
self.__charge = _charge
def setRestEnergy(self, _rest_energy):
self.__restEnergy = _rest_energy
def setMass(self, _mass):
self.__mass = _mass
def setVelocity(self, _velocity):
self.__velocity = _velocity
class Quark:
# Constructor (public)
def __init__(self, _name, _charge, _strangeness):
# Attributes (private)
self.__name = _name
self.__charge = _charge
self.__strangeness = _strangeness
# Getter functions (public)
def getName(self):
return self.__name
def getCharge(self):
return self.__charge
def getStrangeness(self):
return self.__strangeness
class Hadron:
# Constructor (public)
def __init__(self, _name, _charge, _rest_energy, _mass, _velocity, _quarks):
# Attributes (private)
self.__particle = Particle(_name, _charge, _rest_energy, _mass, _velocity)
self.__quarks = _quarks
# Getter functions (public)
def getParticle(self):
return self.__particle
def getQuark(self):
return self.__quarks
def getStrangeness(self):
_quarks = self.__quarks
_strangeness = 0
for _quark in _quarks:
_strangeness += _quark.getStrangeness()
return _strangeness
def getRelCharge(self):
_quarks = self.__quarks
_relCharge = 0
for _quark in _quarks:
_relCharge += _quark.getCharge()
return _relCharge
def getName(self):
return self.__particle.getName()
def getCharge(self):
return self.__particle.getCharge()
def getRestEnergy(self):
return self.__particle.getRestEnergy()
def getMass(self):
return self.__particle.getMass()
def getVelocity(self):
return self.__particle.getVelocity()
# Setter functions (public)
def setName(self, _name):
self.__particle.setName(_name)
def setCharge(self, _charge):
self.__particle.setCharge(_charge)
def setRestEnergy(self, _rest_energy):
self.__particle.setRestEnergy(_rest_energy)
def setMass(self, _mass):
self.__particle.setMass(_mass)
def setVelocity(self, _velocity):
self.__particle.setVelocity(_velocity)我不知道我是不是搞错了,但是当我可以继承粒子类的时候,这似乎是非常浪费的。
我做错了什么吗?
发布于 2020-01-05 16:57:52
这取决于你想要建立什么样的关系。
作文并不总是更好的选择。“组合多于继承”经常被重复,因为继承经常被滥用,其思想是减少您需要编写的代码量。这是完全错误的动机,你的决定的基础上,尽管。
如果您有两个类,A和B,一个粗略的一般指南是:
B 是 A,那么您可能需要继承。B 有一个 A,那么您可能需要作文。在这里的例子中,从我对粒子物理学的极其有限的知识来看,Hadron 是一个 Particle,所以继承可能是更合适的。A contain/have不Hadron a Particle,所以我认为你试图通过强迫这里的构图来对抗颗粒。
发布于 2020-01-07 16:09:48
卡西根尼已经给出了一个很好的答案。我只想补充一下这个部分:
我很难理解为什么(构图)比继承更好。
实际上,它是关于组合/委托的,而不仅仅是组合(它本身并不提供相同的特性)。问题是,继承实际上有两个目的:子类型和实现重用。
子类型表示a“is A”关系--如果B是A的一个(适当的)子类型,您可以在任何地方使用A--实际上Liskov替换原则是相反的:"B是A的一个适当的子类型,如果任何接受A的代码都可以接受B“。请注意,这并没有提到继承或实现,而且这些都不是子类型所必需的(在理论上是这样的)。
现在,对于静态类型化语言,您必须使用继承作为子类型,期间--如果至少有任何实现需要重用,那么您最终将实现重用作为一种奖励。
OTHO的动态类型化不需要继承来进行子类型(当然,只要使用对象的代码不做任何类型检查)--只要有一个兼容的接口就足够了。因此,在Python中,继承主要涉及实现重用。
现在,从技术上讲,通过继承实现重用是一种组合/委托形式--您的对象是它自己类的实例,但也是它的超类的一个实例,而在您的实例本身和它的类上没有解析的任何属性都将在父类上查找。与“手动”组合/委托的主要区别是,继承受到更多的限制--您不能在运行时或在每个实例的基础上更改委托给谁(嗯……实际上,在Python中,您实际上可以在运行时更改实例的类,但实际上这是一个非常糟糕的想法,而且从未像预期的那样工作--在这里完成了xD)。
因此,wrt/实现重用、继承是一种受限且大多是静态的组合/委托形式。对于相当多的用例来说,这是很好的- -通常会或多或少地构建需要继承的抽象基类(-),但是其他一些情况可以用更动态的解决方案来更好地解决(典型的示例是状态和策略设计模式,但还有很多其他的)。
而且,即使仅用于实现重用,继承仍然意味着“是”关系--即使子类不是其基的适当的子类型(任何不兼容都会破坏正确的子类型,并且没有什么可以阻止您用不兼容的签名更改某些子类方法) -,以及Python没有任何“私有继承”的概念,您的子类将公开它继承的所有接口,这并不一定是您想要的(实际上,在执行实现重用时也经常不需要)。当然,如果您决定更改要重用的实现,那么.继承引入了比组合/委托强得多的耦合(这是一种低估)。
一个典型的“初学者错误”示例是继承某些内置集合类型(例如list ),并尝试将其“限制”到他们的特定需求。这从来没有像预期的那样起作用,而且通常需要比使用组合/委派更多的工作。然后,他们意识到(仍然是这样) OrderedDict将是他们自己的用例的一个更好的基础,然后他们有一个问题,客户端代码现在依赖于继承的list接口.从一开始就使用组合/委托就可以避免这里的许多痛苦--将接口限制在相关特性上,而不是泄漏继承的接口,因此将“实现重用”的内容保留到实际情况:客户端代码不应该知道的实现细节。
核心问题实际上是很多非常糟糕的"OO 101“文本,这些文本将继承作为关键的OO特性之一(真正的”关键OO功能“不是封装--不要与基于数据隐藏的BTW和基于类型的多态分派相混淆),导致初学者试图过度使用继承,而没有意识到还有其他--有时更好--解决方案。
长话短说:就像任何其他“金科玉律”一样,当你不理解每个解决方案的利弊时,当你不理解每个解决方案的利弊时,当每一个解决方案都更合适的时候,偏爱组合/授权而不是继承只是一条“规则”-- IOW,就像任何“金科玉律”一样,你不想盲目地接受和应用它(这会导致愚蠢的设计选择),但是--正如你正确地做的那样--质疑它直到你理解它的真正意义,甚至不必再去思考它。
是的:您可能希望了解魔术法 (用于委托)以及描述符协议和内置property类型(用于计算属性支持)(提示:您不需要在Python中使用那些私有属性/公共访问器)。
https://stackoverflow.com/questions/59602093
复制相似问题