我希望根据对象的初始化参数,使用某些默认属性值初始化某些示例。我正在考虑使用嵌套字典作为类属性,但由于某些原因,它感觉很复杂。对于这种情况是否有最佳实践?
class Shape:
metadata = {
3: {"names": ["Triangle", "Triforce"], "color": "sage"},
4: {"names": ["Square", "Box", "Cube"], "color": "dusty rose"},
12: {"names": ["Dodecagon", "Crude circle"], "color": "gold"}
}
colors = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]
def __init__(self, sides, *names):
# All instances will certainly have the same attributes
self.sides = sides
self.names = list(names)
# Most attributes will have automatically generated values based on
# the init parameters
self.color = self.colors[sides % 7]
self.names += [str(sides) + "-gon"]
# But a few will have commonly recognized values which I'd like to set
# manually.
# This is the part I'm not sure how to handle
data = __class__.metadata.get(sides)
if data is not None:
self.names += data["names"]
self.color = data["color"]
我可以在创建对象后添加自定义值,但如果我创建了另一个具有相同初始化参数的对象,它将不会保留这些自定义值(即,我希望我的所有形状(3)对象都具有名称“三角形”)。
2条答案
按热度按时间7xzttuei1#
我认为这感觉很复杂的原因是因为你的形体课试图一次做太多的事情。理想情况下,类应该对程序行为的一部分负责(这是单一责任原则)。
我建议您对代码进行两项主要更改。
不要让shape类负责创建自己
一个形状实际上不需要知道所有其他可能的形状类型,也不需要知道决定它是哪种形状所需的规则。此代码可以抽象为另一个类,因此形状可以集中于包含边、形状和颜色。我建议使用类似于工厂模式的方法来实现这一点(https://en.wikipedia.org/wiki/factory_method_pattern).
考虑使用多态性
如果你计划只将形状作为边名称和颜色的容器,那么你当前的课程将会很好。但是,如果您想添加根据形状类型而变化的功能(例如,如果您想计算它的面积),您将在shapes类中遇到一些复杂的逻辑,这将意味着它再次做了太多的事情。
例如:
k5ifujac2#
我找到了一个解决方案:使用flyweight设计模式。
使用此设计模式,对于每个初始化参数,一个示例只示例化一次,如果使用相同的init参数再次尝试构造,则引用该示例。这类似于某些不可变python内置的对象缓存。
不要将默认属性值保存在类定义中,只需在示例化后设置这些值即可。任何具有相同初始化参数的未来对象都将保留这些自定义值,因为它将引用第一个对象。
通常,这种模式应该用于不可变对象,因为修改一个对象的属性会导致在引用该对象的任何地方都进行更改,这可能会导致意外的结果。然而,在这种情况下,这是可取的行为。