一个最纯粹的技术分享网站,打造精品技术编程专栏!编程进阶网
设计模式Git项目地址:https://github.com/yangchong211/YCDesignBlog
简介: 依赖倒置原则是面向对象设计六大原则之一,强调高层模块不应依赖低层模块,两者应依赖于抽象。通过依赖接口或抽象类而非具体实现,降低模块耦合度,提升系统灵活性和可维护性。本文详解该原则的概念、目标、思想及其实现方式(如依赖注入),并结合多数据库操作、用户购买家电、发送消息等实际案例,深入探讨其应用与优缺点。
依赖倒置原则。单一职责原则和开闭原则的原理比较简单,但是,想要在实践中用好却比较难。而今天要讲到的依赖倒置原则正好相反。
这个原则用起来比较简单,但概念理解起来比较难。比如,下面这几个问题,你看看能否清晰地回答出来:
依赖倒置原则是面向对象设计的六大原则之一,它的定义是:
换句话说,设计中应当依赖于接口或抽象类,而不是依赖于具体实现。这种设计有助于减少模块之间的耦合,增加系统的灵活性和可维护性。
依赖倒置原则的核心思想是面向抽象编程而不是面向具体编程。通过依赖抽象层次(如接口、抽象类),可以让高层模块不依赖具体的实现细节,从而使得系统更具扩展性和灵活性。
例子1:违反依赖倒置原则。假设我们有一个UserService类,它直接依赖于MySQLDatabase类来进行数据操作。
class MySQLDatabase {
public void saveUser(String username) {
// 保存用户到MySQL数据库
System.out.println("Saving " + username + " to MySQL database.");
}
}
class UserService {
private MySQLDatabase database = new MySQLDatabase();
public void addUser(String username) {
database.saveUser(username);
}
}
在这个例子中,UserService类直接依赖于MySQLDatabase类,这是对具体实现的依赖,违反了依赖倒置原则。
如果我们需要将数据库换成PostgresSQLDatabase,或者换成AliSQLDatabase,我们必须修改UserService类,这增加了系统的耦合度和修改的风险。
例子2:遵循依赖倒置原则。可以通过引入一个抽象层来遵循依赖倒置原则。
// 抽象层:定义一个接口,供不同的数据库实现
interface Database {
void saveUser(String username);
}
// 具体实现:MySQL数据库
class MySQLDatabase implements Database {
public void saveUser(String username) {
System.out.println("Saving " + username + " to MySQL database.");
}
}
// 具体实现:PostgreSQL数据库
class PostgreSQLDatabase implements Database {
public void saveUser(String username) {
System.out.println("Saving " + username + " to PostgreSQL database.");
}
}
// 高层模块:UserService类依赖于抽象接口,而不是具体实现
class UserService {
private Database database;
public UserService(Database database) {
this.database = database;
}
public void addUser(String username) {
database.saveUser(username);
}
}
在这个例子中,UserService类依赖于Database接口,而不是具体的数据库实现。
这意味着如果我们想更换数据库,只需要传入不同的实现类,而不需要修改UserService类本身。这样做遵循了依赖倒置原则,降低了模块之间的耦合度。
从这个例子可知,定义数据库抽象层供不同的数据库实现,然后在UserService类依赖于抽象接口而不是具体实现,可以充分降低代码耦合度,可以快速拓展其他数据库实现。
例子1:违反依赖倒置原则。假设顾客,想要买冰箱,洗衣机,电视,或者其他电器,它直接依赖于Customer类来进行数据操作。
public class Customer {
public void buyFridge() {
System.out.println("购买冰箱");
}
public void buyTelevision() {
System.out.println("购买电视");
}
}
例子2:遵循依赖倒置原则。可以通过引入一个抽象层来遵循依赖倒置原则。
/**
* 商品接口
*/
public interface IGood {
/**
* 购买商品
*/
void buy();
}
public class Customer {
public void buy(IGood iGood) {
iGood.buy();
}
}
/**
* 冰箱商品
*/
public class FridgeGood implements IGood {
@Override
public void buy() {
System.out.println("购买冰箱");
}
}
/**
* 电视商品
*/
public class TelevisionGood implements IGood {
@Override
public void buy() {
System.out.println("购买电视");
}
}
/**
* 洗衣机商品
*/
public class WashMachineGood implements IGood {
@Override
public void buy() {
System.out.println("购买洗衣机");
}
}
public class Main {
public static void main(String[] args) {
Customer customer = new Customer();
customer.buy(new FridgeGood());
customer.buy(new TelevisionGood());
customer.buy(new WashMachineGood());
}
}
例子1:违反依赖倒置原则。假设用户,可以通过邮件,短信息,信件等发送消息,下面这种就不太友好。
public class Notification {
public void email(String cellphone, String message) {
System.out.println("通过邮件发送消息");
}
public void message(String cellphone, String message) {
System.out.println("通过短信息发送消息");
}
public void letter(String cellphone, String message) {
System.out.println("通过信件发送消息");
}
}
例子2:遵循依赖倒置原则。可以通过引入一个抽象层来遵循依赖倒置原则。
public class Notification {
private MessageSender messageSender;
public Notification(MessageSender messageSender) {
this.messageSender = messageSender;
}
public void sendMessage(String cellphone, String message) {
this.messageSender.send(cellphone, message);
}
}
public interface MessageSender {
void send(String cellphone, String message);
}
// 邮件发送类
public class EmailSender implements MessageSender {
@Override
public void send(String cellphone, String message) {
//....
}
}
// 短信发送类
public class SmsSender implements MessageSender {
@Override
public void send(String cellphone, String message) {
//....
}
}
// 站内信发送类
public class InboxSender implements MessageSender {
@Override
public void send(String cellphone, String message) {
//....
}
}
依赖注入(Dependency Injection, DI)是一种设计模式,旨在将对象的依赖关系从对象内部转移到外部管理,从而降低类之间的耦合度,提高代码的可维护性和可测试性。
依赖注入(Dependency Injection,DI)是一种通过将依赖关系从高层模块解耦的方式,常用于实现依赖倒置原则。
依赖倒置原则(Dependency Inversion Principle,DIP)和依赖注入(Dependency Injection,DI)是面向对象设计中两个相关但不同的概念。
依赖注入是实现依赖倒置原则的一种常见方式,但并不是唯一的方式。依赖倒置原则还可以通过工厂模式、策略模式等其他设计模式来实现。
这些设计模式的共同点是,它们都通过引入抽象接口或基类,将高层模块与具体实现解耦,使得高层模块依赖于抽象而非具体实现。符合依赖倒置原则的设计思想。
模块 | 描述 | 备注 |
---|---|---|
GitHub | 多个YC系列开源项目,包含Android组件库,以及多个案例 | |
博客汇总 | 汇聚Java,Android,C/C++,网络协议,算法,编程总结等 | |
设计模式 | 六大设计原则,23种设计模式,设计模式案例,面向对象思想 | |
Java进阶 | 数据设计和原理,面向对象核心思想,IO,异常,线程和并发,JVM | |
网络协议 | 网络实际案例,网络原理和分层,Https,网络请求,故障排查 | |
计算机原理 | 计算机组成结构,框架,存储器,CPU设计,内存设计,指令编程原理,异常处理机制,IO操作和原理 | |
学习C编程 | C语言入门级别系统全面的学习教程,学习三到四个综合案例 | |
C++编程 | C++语言入门级别系统全面的教学教程,并发编程,核心原理 | |
算法实践 | 专栏,数组,链表,栈,队列,树,哈希,递归,查找,排序等 | |
Android | 基础入门,开源库解读,性能优化,Framework,方案设计 |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。