在我们日常工作中,代码写着写着就出现下列的一些臭味。但是还好我们有SOLID这把‘尺子’, 可以拿着它不断去衡量我们写的代码,除去代码臭味。这就是我们要学习SOLID原则的原因所在。
一个很好的例子:在我们封装request库时,我们需要实现以下4个方法.
class MyRequestClient: def post(self): pass def get(self): pass def update(self): pass def delete(self): pass #上面的方法就是属于同一职责。 如何还有其他的方法,那么这个类就不符合单一职责原则。 #例增加以下方法: def get_db_data(self): pass def to_object(self): pass 首先我们来看一个违反OCP原则的例子。
#bad codedef circle_draw(): print(f"this is circle draw")def square_draw(): print(f"this is square draw")def draw_all_shape(shapes): for shape in shapes: if shape == "circle": circle_draw() if shape == "square": square_draw()这段代码的问题是如果再有新的类型需要draw, 我们需要修改draw_all_shape函数来适配新的类型。
我们定义了一个抽象类Shape, 子类Square和Circle继承Shape. 并且在子类中重写了父类的方法。函数draw_all_shape是绘制所有图形。

from typing import Listfrom abc import ABCMeta, abstractmethodclass Shape(metaclass=ABCMeta): @abstractmethod def draw(self): passclass Square(Shape): def draw(self): print(f"this is square draw")class Circle(Shape): def draw(self): print(f"this is circle draw")def draw_all_shape(shapes: List[Shape]): for shape in shapes: shape.draw()我们定义了一个抽象类Shape, 子类Square和Circle继承Shape. 并且在子类中重写了父类的方法。函数draw_all_shape是绘制所有图形。
def circle_draw(): print(f"this is circle draw")def square_draw(): print(f"this is square draw")def draw_all_shape_by_function(data: Dict[str,Callable]): for key,value in data.items(): value()data = { "circle": circle_draw, "square": square_draw}draw_all_shape_by_function(data=data)Shape.无需修改shape类和draw_all_shape就可以实现三角形类的绘制。首先我们来看一段违法LSP的例子
from typing import Iterableclass User(): def __init__(self, user: str) -> None: self.user = user def disable(self) -> None: print(f"{self.user} disable!") class Admin(User): def __init__(self, user: str = "Admin") -> None: self.user = user def disable(self): raise "Admin do not disable!" def delete_user(users: Iterable[User]): for user in users: user.disable()当执行delete_user时,就会抛出TypeError 错误,Admin类中disable方法违法了LSP替换原则。
#Goodfrom typing import Iterableclass User(): def __init__(self, user: str) -> None: self.user = user def allow_disable(self): return True def disable(self) -> None: print(f"{self.user} disable!") class Admin(User): def __init__(self, user: str = "Admin") -> None: self.user = user def allow_disable(self): return False def delete_user(users: Iterable[User]) -> None: for user in users: if user.allow_disable: user.disable()allow_disable 的方法,解决了Admin类不能disable的问题。首先看一个违反DIP原则的例子:
class Lamp: def turn_on(self): print("turn on the lamp") def turn_off(self): print("turn off the lamp")class Button(): def __init__(self) -> None: self.lamp = Lamp() def turn_on(self): return self.lamp.turn_on() def turn_off(self): return self.lamp.turn_off()当有一天,button需要控制televsion时,就需要修改Button类。Button和Lamp 具有强耦合关系。所以,当Lamp变动时,会影响到Button类。违法了DIP原则的高层模块依赖于底层模块。

定义一个抽象类ElectricAppliance Button 和 Lamp 都依赖这个抽象类。 解决了Button和Lamp 具有强耦合的问题。
class ElectricAppliance(metaclass=ABCMeta): @abstractmethod def turn_on(self): pass @abstractmethod def turn_off(self): passclass Lamp(ElectricAppliance): def turn_on(self): print("turn on the lamp") def turn_off(self): print("turn off the lamp")class Television(ElectricAppliance): def turn_on(self): print("turn on the televison") def turn_off(self): print("turn off the televison")class Button: def __init__(self, electric_appliance: ElectricAppliance) -> None: self.electric_appliance = electric_appliance def turn_on(self): self.electric_appliance.turn_on() def turn_off(self): self.electric_appliance.turn_off()首先来看一个违反ISP原则的例子:
class Animal(metaclass=ABCMeta): @abstractclassmethod def run(self): pass @abstractclassmethod def speak(self): pass @abstractclassmethod def fly(self): passclass Dog(Animal): def run(self): return "Dog Running" def speak(self): return "Dog Speaking" def fly(self): raise TypeError("Dog can not fly")class Bird(Animal): def run(self): raise TypeError("Bird can not run") def speak(self): return "Bird Speaking" def fly(self): return "Bird fly"def fly_animal(animals: Iterable[Animal]): for animal in animals: animal.fly()
当我们执行fly_animal时,就会抛出TypeError的错误。此时Animal抽象类是一个胖类,违法了ISP原则。

#goodclass FlyingAnimal(metaclass=ABCMeta): @abstractclassmethod def fly(self): passclass RunningAnimal(metaclass=ABCMeta): @abstractclassmethod def run(self): passclass TalkingAnimal(metaclass=ABCMeta): @abstractclassmethod def talk(self): passclass Dog(RunningAnimal,TalkingAnimal): def run(self): return "Dog Running" def talk(self): return "Dog Speaking"class Bird(FlyingAnimal, TalkingAnimal): def talk(self): return "Bird Speaking" def fly(self): return "Bird fly"def fly_animal(animals: Iterable[FlyingAnimal]): for animal in animals: print(animal.fly())本文来自博客园,作者:烟熏柿子学编程,转载请注明原文链接:https://www.cnblogs.com/aaron-948/p/16235001.html