想象一下我在 python 中有以下内容(实际语言并不重要,因为我在其他语言(如 php)中也遇到了问题。基类“CarModel”和来自“CarModel”的派生类“TruckModel”。
class CarModel:
def __init__(self):
self.__wheel_count: int = 0
def set_wheel_count(self, value: int) -> None:
self.__wheel_count = value
class TruckModel(CarModel):
def __init__(self):
super().__init__()
self.__load_in_kg: int = 0
def set_load_in_kg(self, value: int) -> None:
self.__load_in_kg= value
如果我现在有一个映射类,它应该转换为例如我的模型的字典,如何为我的派生类重用映射方法? 特别是如果我有一个包含很多 setter 方法的基类,我必须重复代码,这是我不喜欢的(“干”)。
class VehicleMapper:
def map_car_dict_to_car_model(dict: Dict) -> CarModel:
model: CarModel = CarModel()
model.set_wheel_count(dict['wheelCount'])
return model
def map_truck_dict_to_truck_model(dict: Dict) -> TruckModel:
model: TruckModel= TruckModel()
model.set_load_in_kg(dict['loadInKg'])
model.set_wheel_count(dict['wheelCount']) # ??? How can I re-use the map-method for the base class here ???
return model
我可以将映射方法移至模型类,这样就可以了。但我被告知,模型类应该只“保存”数据,而不应该做任何事情。这就是为什么有映射器类,对吗?
更干净、更可靠的方法是使用单独的映射器/工厂。而且更合理,因为在您的情况下,您还需要从字典键到相应模型属性名称的可配置映射。
考虑以下模式:
class CarModel:
def __init__(self):
self.__wheel_count: int = 0
def wheel_count(self, value: int) -> None:
self.__wheel_count = value
wheel_count = property(None, wheel_count)
class TruckModel(CarModel):
def __init__(self):
super().__init__()
self.__load_in_kg: int = 0
def load_in_kg(self, value: int) -> None:
self.__load_in_kg= value
load_in_kg = property(None, load_in_kg)
class VehicleFactory:
"""Vehicle base factory"""
__model__ = None
__map_keys__ = None
@classmethod
def create(cls, data):
model = cls.__model__()
for k, attr in cls.__map_keys__.items():
setattr(model, attr, data[k])
return model
class CarFactory(VehicleFactory):
__model__ = CarModel
__map_keys__ = {'wheelCount': 'wheel_count'}
class TruckFactory(VehicleFactory):
__model__ = TruckModel
__map_keys__ = {'wheelCount': 'wheel_count',
'loadInKg': 'load_in_kg'}
car = CarFactory.create({'wheelCount': 4})
print(vars(car)) # {'_CarModel__wheel_count': 4}
truck = TruckFactory.create({'wheelCount': 4, 'loadInKg': 500})
print(vars(truck)) # {'_CarModel__wheel_count': 4, '_TruckModel__load_in_kg': 500}
class CarModel:
mapping = {}
@staticmethod
def _key(key, mapping=mapping):
def decorator(func):
mapping[key] = func
return decorator
@classmethod
def from_dict(cls, d: dict):
instance = cls()
for key, value in d.items():
cls.mapping[key](instance, value)
return instance
def __init__(self):
self.__wheel_count: int = 0
@_key('wheelCount')
def set_wheel_count(self, value: int) -> None:
self.__wheel_count = value
class TruckModel(CarModel):
def __init__(self):
super().__init__()
self.__load_in_kg: int = 0
@CarModel._key('loadInKg')
def set_load_in_kg(self, value: int) -> None:
self.__load_in_kg= value
这样:
print(vars(CarModel.from_dict({'wheelCount': 4})))
print(vars(TruckModel.from_dict({'wheelCount': 6, 'loadInKg': 8000})))
输出:
{'_CarModel__wheel_count': 4}
{'_CarModel__wheel_count': 6, '_TruckModel__load_in_kg': 8000}
演示:https://ideone.com/xp2IAB