Python中的依赖项反转

2024-09-30 22:28:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我已经开始将SOLID principles应用到我的项目中。所有这些对我来说都很清楚,除了依赖项反转,因为在Python中,我们并没有改变定义另一个类中某个类类型的变量(或者可能只是我不知道)。所以我已经用两种形式实现了依赖倒置原理,我想知道哪一种是正确的,我怎样才能纠正它们。这是我的密码:

d1.py

class IFood:
    def bake(self, isTendir: bool): pass
    
class Production:
    def __init__(self):
        self.food = IFood()
    
    def produce(self):
        self.food.bake(True)
        
class Bread(IFood):
    def bake(self, isTendir:bool):
        print("Bread was baked")

d2.py

from abc import ABC, abstractmethod
class Food(ABC):
    @abstractmethod
    def bake(self, isTendir): pass
    
class Production():
    def __init__(self):
        self.bread = Bread()
    
    def produce(self):
        self.bread.bake(True)
        
class Bread(Food):
    def bake(self, isTendir:bool):
        print("Bread was baked")

Tags: pyselftruefoodinitdefpassclass
2条回答

原则

罗伯特·C·马丁对依赖倒置原则的定义 由两部分组成:

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
  2. Abstractions should not depend on details. Details should depend on abstractions.

只是想澄清一下。。。模块可以是函数、类、文件。。。一段代码

错误

假设你有一个程序需要你烤面包

在更高的级别上,您可以调用cook()

实现这一点的一个糟糕方法是创建一个函数,该函数既可以烹饪,也可以创建面包

def cook():
    bread = Bread()
    bread.bake()

cook()

这不好

如您所见,cook函数依赖于Bread

那么,如果你想烤饼干怎么办

新手犯的一个错误是添加如下字符串参数:

def cook(food: str):
    if food == "bread":
        bread = Bread()
        bread.bake()
    if food == "cookies":
        cookies = Cookies()
        cookies.bake()

cook("cookies")

这显然是错误的。因为通过添加更多的食物,你会改变你的代码,你的代码会被很多if语句弄得一团糟。而且它几乎打破了所有的原则

解决方案

因此,您需要cook函数,它是一个更高级别的模块,而不是依赖于像BreadCookies这样的较低级别的模块

因此,我们唯一需要的是我们可以烘烤的东西。我们会烤它。现在正确的方法是实现一个接口。在Python中,这是不必要的,但强烈建议保持代码干净并经得起未来考验

If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.

他们说

现在让我们反转依赖关系

from abc import ABC, abstractmethod
class Bakable(ABC):
    @abstractmethod
    def bake(self):
        pass

def cook(bakable:Bakable):
    bakable.bake()

现在cook函数依赖于抽象。不是在面包上,不是在饼干上,而是在抽象上。任何Bakable现在都可以烘焙了

通过实现接口我们确信每个Bakable都会有一个bake()方法来做一些事情

但是现在cook函数不需要知道。 cook函数将烘焙任何Bakable的内容

依赖项现在转到客户端。客户就是那个想要烤东西的人。客户机是一段将使用cook函数的代码。客户知道要烤什么

现在通过查看cook函数,客户机知道cook函数等待接收Bakable而只接收Bakable

那么让我们做一些面包

class Bread(Bakable):
    def bake():
        print('Smells like bread')

现在,让我们创建一些cookies

class Cookies(Bakable):
    def bake():
        print('Cookie smell all over the place')

好的!现在我们来煮吧

cookies = Cookies()
bread = Bread()
cook(cookies)
cook(bread)
# define a common interface any food should have and implement
class IFood:
    def bake(self): pass
    def eat(self): pass

class Bread(IFood):
    def bake(self):
        print("Bread was baked")
    def eat(self):
        print("Bread was eaten")

class Pastry(IFood):
    def bake(self):
        print("Pastry was baked")
    def eat(self):
        print("Pastry was eaten")

class Production:
    def __init__(self, food): # food now is any concrete implementation of IFood
        self.food = food # this is also dependnecy injection, as it is a parameter not hardcoded

    def produce(self):
        self.food.bake()  # uses only the common interface

    def consume(self):
        self.food.eat()  # uses only the common interface

使用它:

ProduceBread = Production(Bread())
ProducePastry = Production(Pastry())

相关问题 更多 >