传统依赖
假设我们有一个 UserController 类,负责处理用户的相关操作,包括创建用户、删除用户等。该类直接依赖于具体的数据库操作类 UserRepository 来执行与数据库的交互。
class UserController:
def __init__(self):
self.userRepository = UserRepository() # 具体的数据库操作类
def createUser(self, userData):
self.userRepository.save(userData)
def deleteUser(self, userId):
self.userRepository.delete(userId)
在这个例子中,UserController 类直接依赖于 UserRepository 类的具体实现。这种直接依赖关系会导致以下问题:
1 高层模块与低层模块的强耦合:UserController 类与 UserRepository 类紧密耦合在一起,高层模块依赖于低层模块的具体实现细节。
2 难以扩展和修改:如果我们想要更换数据库操作类为另一个实现,或者引入缓存层来提高性能,那么就需要修改 UserController 类的代码。这违背了开闭原则,应该对扩展开放,对修改封闭。
依赖倒置
通过应用依赖倒置原则,我们可以改进这个例子。首先,我们引入一个抽象的 UserRepositoryInterface 接口,定义了用户操作的方法。
class UserRepositoryInterface(ABC):
@abstractmethod
def save(self, userData):
pass
@abstractmethod
def delete(self, userId):
pass
然后,让 UserRepository 类实现该接口。
class UserRepository(UserRepositoryInterface):
def save(self, userData):
# 具体的数据库保存操作
def delete(self, userId):
# 具体的数据库删除操作
最后,我们修改 UserController 类,将其依赖关系倒置至抽象的接口。
class UserController:
def __init__(self, userRepository):
self.userRepository = userRepository
def createUser(self, userData):
self.userRepository.save(userData)
def deleteUser(self, userId):
self.userRepository.delete(userId)
现在,UserController 类不再依赖于具体的数据库操作类,而是依赖于抽象的 UserRepositoryInterface 接口。这样,高层模块与低层模块之间的耦合得到解耦,高层模块对接口的依赖性使得系统更加灵活和可扩展。
依赖倒置实现底层数据库操作的切换
当通过依赖注入将不同的实现类传入 UserController 类时,可以实现底层数据库操作的切换。下面是一个示例:
# 定义抽象接口 UserRepositoryInterface
class UserRepositoryInterface:
def save(self, userData):
pass
def delete(self, userId):
pass
# 定义具体的数据库操作类 MySQLUserRepository
class MySQLUserRepository(UserRepositoryInterface):
def save(self, userData):
# 在 MySQL 数据库中保存用户数据的具体实现
print("Saving user data in MySQL database")
def delete(self, userId):
# 在 MySQL 数据库中删除用户数据的具体实现
print("Deleting user data from MySQL database")
# 定义具体的数据库操作类 PostgreSQLUserRepository
class PostgreSQLUserRepository(UserRepositoryInterface):
def save(self, userData):
# 在 PostgreSQL 数据库中保存用户数据的具体实现
print("Saving user data in PostgreSQL database")
def delete(self, userId):
# 在 PostgreSQL 数据库中删除用户数据的具体实现
print("Deleting user data from PostgreSQL database")
# UserController 类依赖于 UserRepositoryInterface 接口
class UserController:
def __init__(self, userRepository):
self.userRepository = userRepository
def createUser(self, userData):
self.userRepository.save(userData)
def deleteUser(self, userId):
self.userRepository.delete(userId)
# 使用 MySQLUserRepository 进行数据库操作
mysql_repository = MySQLUserRepository()
controller = UserController(mysql_repository)
controller.createUser("User1")
controller.deleteUser(1)
# 使用 PostgreSQLUserRepository 进行数据库操作
postgresql_repository = PostgreSQLUserRepository()
controller = UserController(postgresql_repository)
controller.createUser("User2")
controller.deleteUser(2)
在上述示例中,通过将不同的实现类 MySQLUserRepository 和 PostgreSQLUserRepository 遵循 UserRepositoryInterface 接口传入 UserController 类的构造函数,可以切换底层数据库操作的实现。通过调用 createUser 和 deleteUser 方法,实际执行的数据库操作取决于传入的实现类。
这样,可以在不改变 UserController 类的代码的情况下,通过传入不同的实现类来切换底层的数据库操作。这种灵活性使得我们可以根据需要选择不同的数据库或数据存储方式,而不需要修改 UserController 类的实现。
MySQLUserRepository 和 PostgreSQLUserRepository 遵循 UserRepositoryInterface 接口,这一点符合里氏替换原则(Liskov Substitution Principle)。无论是使用 MySQLUserRepository 还是 PostgreSQLUserRepository,都不会破坏代码的正确性,可以在不修改代码的情况下进行切换。
这样的设计支持代码的灵活性和可扩展性,同时也符合开闭原则(Open-Closed Principle),即对扩展开放、对修改封闭。
总结
依赖倒置原则(Dependency Inversion Principle,DIP)是SOLID原则中的关键原则之一。它在软件设计中起着重要的作用。
依赖倒置原则强调高层模块(抽象)不应该直接依赖于低层模块(具体实现),而是应该依赖于抽象。这意味着抽象应该定义清楚和稳定的接口,而具体实现则应该依赖于接口,以实现解耦和可替换性。
通过依赖倒置,可以实现以下好处:
-
解耦和灵活性:通过依赖抽象接口而不是具体实现,高层模块和低层模块之间的耦合度降低,可以独立修改、测试和扩展各个模块。
-
可替换性和可扩展性:通过定义抽象接口,可以轻松替换具体实现,例如使用不同的数据库、第三方库或服务。
-
单元测试和模拟:依赖倒置使得单元测试变得容易,可以使用模拟对象或测试替身来模拟依赖,而无需实际依赖的具体实现。
-
代码可读性和可维护性:依赖倒置原则提供了更清晰的代码结构,使得代码易于理解、维护和重构。
总之,依赖倒置原则是面向对象设计中的重要原则之一,它能够帮助我们构建松耦合、可扩展和可维护的软件系统。通过依赖抽象而不是具体实现,我们能够实现代码的灵活性和可替换性,提高系统的可靠性和可测试性。
我理解,就是规范具体类的接口,使其符合某个抽象的规定,这样就可以随意切换具体类仍能使程序正常运行。
依赖倒置原则的关键之一就是通过定义抽象接口来规范具体类的行为,从而实现对具体类的解耦。通过依赖抽象而不是具体实现,可以使代码更加灵活和可扩展,同时降低了代码之间的耦合度。
通过依赖倒置原则,我们可以定义一个抽象接口(或者抽象类)来描述一组相关的操作或行为,然后具体的类可以实现这个接口。这样,我们可以在不改变高层模块的代码的情况下,通过切换具体类的实现来改变程序的行为。
注意:我正在学习python,这是我的个人理解,如有任何错误,欢迎指正。谢谢。