我尝试根据 SOLID 规则培养设计技能。
有一个大的逻辑相关类代表一个真实世界的对象。假设一个类中有大约 40 个方法来表示该对象的行为。
大概有数百种方法。如果它们在逻辑上连接,那么这是允许的,据我所知。
但是使用它们很不方便。我希望类别可以更方便地使用课程。
用三种不同的方式写了一个类似的课程。根据建议,我尝试使用组合而不是继承。
汽车——最简单的,但如果有四十或一百种方法,那就不方便了,过一段时间就很难弄清楚了。
Car2 -是一个组合,但违反了 SOLID 规则的“Demeter 法则”,因为客户不仅知道 Car2,还知道他的朋友。
Car3 -不违反任何东西,封装了每个类,但是方法的数量和第一个版本一样,不是很方便。
在我看来,第二个版本是最方便的。第三个在方法的数量上与第一个没有区别,但似乎是最正确的一个。
如果有人明白,指出错误。我采取了正确的方法吗?哪种方法最合适?
class Car:
def __init__(self):
self._speed = 0
self._name = "Car"
def __str__(self):
return self.name
@property
def speed(self):
return self._speed
@property
def name(self):
return self._name
def turn_left(self): pass
def turn_right(self): pass
def accelerate(self): pass
def brake(self): pass
def windscreen_wiper_on(self): pass
def windscreen_wiper_of(self): pass
# -----------------------------------------------------------------------
class Car2():
def __init__(self):
self._speed = 0
self._name = "Car"
self._stering_wheel = SteringWheel(self)
self._gas_pedal = GasPedal(self)
self._windscreen_wiper = WindscreenWiper(self)
def __str__(self):
return self.name
@property
def speed(self):
return self._speed
@speed.setter
def speed(self, value):
self._speed = value
print("Новая скорость машины:", self._speed)
@property
def name(self):
return self._name
@property
def stering_wheel(self):
return self._stering_wheel
@property
def gas_pedal(self):
return self._gas_pedal
@property
def windscreen_wiper(self):
return self._windscreen_wiper
# -----------------------------------------------------------------------
class Car3:
def __init__(self):
self._speed = 0
self._name = "Car"
self._stering_wheel = SteringWheel(self)
self._gas_pedal = GasPedal(self)
self._windscreen_wiper = WindscreenWiper(self)
def __str__(self):
return self.name
@property
def speed(self):
return self._speed
@speed.setter
def speed(self, value):
self._speed = value
print("Новая скорость машины:", self._speed)
def turn_left(self):
self._stering_wheel.turn_left()
def turn_right(self):
self._stering_wheel.turn_right()
def accelerate(self):
car.gas_pedal.press()
def brake(self):
car.gas_pedal.depress()
def windscreen_wiper_on(self):
car.windscreen_wiper.on()
def windscreen_wiper_of(self):
car.windscreen_wiper.off()
# ---------------------------- Компоненты машины ------------------------------
class SteringWheel:
def __init__(self, car: Car):
self._car = car
def rotate_left(self):
print(self._car.name, "повернула влево")
def rotate_right(self):
print(self._car.name, "повернула вправо")
class GasPedal:
def __init__(self, car: Car):
self._car = car
def press(self):
self._car.speed += 1
def depress(self):
self._car.speed -= 1
class WindscreenWiper:
def __init__(self, car: Car):
self._car = car
def on(self):
print("Дворники", self._car.name, "очищают окно.")
def off(self):
print("Дворники", self._car.name, "выключились.")
# ---------------------------------------------------------------------------
def main():
car = Car2()
car.gas_pedal.press()
car.gas_pedal.press()
car.gas_pedal.depress()
car.windscreen_wiper.on()
car.windscreen_wiper.off()
car.stering_wheel.rotate_left()
main()
第二个选项更简单明了。我们只需要稍微不同地看待它。
得墨忒耳定律说,“司机”不应该知道汽车是如何被控制的——通过方向盘、方向盘或绳索。但是如果一辆车总是有一个实体来控制(经理),那么它可以被移动到一个单独的类并用作
car.steering.something。这同样适用于
gas_pedal- 你不能以这种形式在外面“展示”它。突然间,取而代之的是变阻器或杠杆。但是,如果您将其“设置”为速度控制 (accelerator),那么一切都会井井有条。如果你能挑出一个类的所有后代都实现的行为,并且这种行为与类密不可分(即每台机器都会有一个控制器和speed_controller),那么很有可能将它移到一个单独的类(并替换此类中的不同实现)。
本质上,通过 2 种方式,您可以获得:
A. 方法的树分组:
B. 替换执行组件的可能性。
PS 最后,对于反思 - 最佳实践在 80-99.9% 的情况下可能是好的,但是当 goto 或 12 个输入参数,或者 120 行方法将是合理的,比以下更容易或更好时,总会有 %一般好的规则。