我有一个类,我们称之为Animal
,在一个库中定义。
在一个单独的库中,我想根据它们的子类型用颜色表示这些Animal
。例如,Lion
对象为红色。 我希望任何Animal
都有一个默认颜色,以防颜色不是为其定义的颜色。 我还希望有Animal
的子类型,例如Feline
,它们本身可以定义默认颜色以取代通用Animals
的颜色。
实现此类目标的简单方法如下。(我在这里使用Python来演示,但我认为这是一个与语言无关的问题。
class Animal:
def __init__(self):
self.color = Black
class Feline(Animal):
def __init__(self):
super.__init__()
self.color = Blue
class Dog(Animal):
pass # self.color == Black
class Cat(Feline):
pass # self.color == Blue
class Lion(Feline):
def __init__(self):
super.__init__()
self.color = Red
从本质上讲,每个Animal
都有一个由自己或定义它的最早祖先定义的color
。
但是,我不希望Animal
的color
是一个字段,即Animal
的表示应该与Animal
本身分开。
所以,相反,我正在运行更像这样的东西:
# animal.py
class Animal:
pass
class Feline(Animal):
pass
class Dog(Animal):
pass
class Cat(Feline):
pass
class Lion(Feline):
pass
# animal_colors.py
default_colors: dict[type, Color] = {
Animal: Black,
Feline: Blue,
Lion: Red,
# Notice how Cat, and Dog aren't defined here
}
def get_color(animal: Animal, lookup_table:dict[type, Color]=default_colors) -> Color:
mro = type(animal).__mro__
assert Animal in mro, "Non Animal class passed to get_color()"
for t in mro:
try:
return lookup_table[t]
except KeyError:
continue
raise RuntimeError("Animal object has no defined color")
这样get_color(my_animal)
将为动物返回所需的颜色。
然而,这对我来说简直是错误的方法......我认为我不应该干涉这样一个简单用例的__mro__
。 我正在寻找更好的方法来解决这个问题,即本质上是在类层次结构之外定义属性和默认值。
最后我想提的是,就我的情况而言,拥有Animal
或Feline
的实例是有意义的,这在传统上是抽象类。 即对象应该能够在层次结构的每个级别实例化。如果需要,也许我可以DefaultAnimal
并DefaultFeline
子类型。
*奖励问题:我相信这种方法违反了利斯霍夫替换原则(如果应该Blue
Feline
,则不应Red
Lion
)有更好的方法来解决这个问题吗?
听起来您要查找的是类属性。
class Animal:
color = Black
class Feline(Animal):
color = Blue
class Lion(Feline):
color = Red
这定义了属于类本身的属性,而不是属于其实例的属性。它们可以通过实例或类进行访问。例如
Lion.color == Red # attribute on the class object
Lion().color == Red # atteibute on the instance object
Python确实支持抽象类,但它们很少使用。Python是一种高度实用的语言,它避开了Java,C#或C++等强类型OO语言的许多形式。例如,它没有访问修饰符,没有实际信息隐藏,没有接口,并且除了计算属性之外很少使用属性。继承在日常的Python编程中极为罕见。
至于 LSP,您没有违规,至少通常理解主体的方式是这样,因为您可以在 Lion 上访问与猫科动物相同的属性,并获取相同类型的值。LSP 通常被理解为在类型级别而不是值级别运行。