面向接口编程(松耦合)

### **面向接口编程(松耦合)的核心思想**
**核心原则**:**调用方(如Service、测试类)只依赖接口(`BookDao`),不关心具体实现类(`BookDaoImpl`)**。  
这意味:
1. **接口定义稳定的契约**(方法签名、行为规范),一旦发布应尽量不改动。
2. **实现类可以自由替换**(如`BookDaoImpl`改为`BookDaoJdbcImpl`),只要满足接口的契约,调用方无需感知。

---

### **具体场景举例**
假设你有一个接口和两个实现类:
```java
// 接口(契约)
public interface BookDao {
    Book findById(Long id);
}

// 实现类1:基于JDBC
@Repository
public class BookDaoJdbcImpl implements BookDao {
    @Override
    public Book findById(Long id) { /* JDBC查询逻辑 */ }
}

// 实现类2:基于MyBatis
@Repository
public class BookDaoMyBatisImpl implements BookDao {
    @Override
    public Book findById(Long id) { /* MyBatis查询逻辑 */ }
}
```

#### **场景1:更换实现类**
- **需求变化**:从JDBC切换到MyBatis。
- **修改点**:
  1. **新增实现类** `BookDaoMyBatisImpl`。
  2. **调整Spring的依赖配置**(如用`@Primary`标记新实现类,或通过`@Qualifier`指定Bean名称)。
- **无需修改的地方**:
  - **接口`BookDao`**:保持原有方法定义。
  - **调用方(如Service、测试类)**:它们仍然通过`@Autowired private BookDao bookDao;`注入,代码无需改动。

---

#### **场景2:扩展接口功能**
- **需求变化**:新增一个方法`List<Book> findAll()`。
- **修改点**:
  1. **修改接口**:在`BookDao`中添加新方法。
  2. **修改所有实现类**:必须实现`findAll()`方法。
- **代价**:此时所有实现类都需要调整,说明接口的稳定性被破坏。  
  **优化方案**:设计接口时应尽量前瞻,或通过**默认方法**(Java 8+)或**抽象类**提供部分实现,减少对实现类的冲击。

---

### **关键结论**
1. **理想情况下**:接口稳定不变,只需修改实现类。
2. **实际开发中**:
   - 接口可能需要扩展,但应通过**向后兼容**的方式(如新增方法不影响已有功能)。
   - 如果必须修改接口的已有方法,说明设计有缺陷,此时松耦合的优势会被削弱。

---

### **为什么强调“尽量不修改接口”?**
- **接口是多方契约**:调用方(Service、测试)和实现方(DaoImpl)都依赖接口。
- **修改接口的影响**:
  - 所有实现类必须同步修改。
  - 调用方可能需要调整代码(例如处理新方法)。
- **如何避免接口频繁修改**:通过**开闭原则**(对扩展开放,对修改关闭),通过新增接口或组合方式扩展功能。

---

### **实际开发中的最佳实践**
1. **接口定义阶段**:充分讨论需求,确保接口覆盖核心功能。
2. **接口扩展阶段**:
   - 优先通过**新增方法**而非修改已有方法。
   - 使用`default`方法提供默认实现(Java 8+特性):
     ```java
     public interface BookDao {
         Book findById(Long id);
         
         // 新增方法,提供默认实现
         default List<Book> findAll() {
             throw new UnsupportedOperationException("Not implemented yet");
         }
     }
     ```
3. **实现类替换**:通过Spring的依赖注入机制(如`@Primary`、`@Qualifier`)无缝切换。

---

### **总结**
- **你的理解正确**:面向接口编程的核心是**通过接口隔离变化**,大部分情况下只需调整实现类,无需修改接口。
- **注意事项**:接口本身的设计需足够健壮,避免频繁改动。若必须修改接口,需评估对系统的影响。

//只用修改接口的实现类 而不用修改接口
default List<Book> findAll() {
             throw new UnsupportedOperationException("Not implemented yet");
         }
     }

这段代码是Java 8及以上版本中**接口的默认方法(Default Method)**,它的作用如下:

---

### **1. 代码示例**

```java
public interface BookDao {
    // 原有方法
    Book findById(Long id);
    
    // 新增的默认方法
    default List<Book> findAll() {
        throw new UnsupportedOperationException("Not implemented yet");
    }
}


```

---

### **2. 默认方法的作用**
- **向后兼容性**:允许接口在不破坏已有实现类的情况下**新增方法**。
  - 旧实现类(如`BookDaoImpl`)无需立即实现`findAll()`,但调用时会抛出异常。
  - 新实现类(如`BookDaoJdbcImpl`)可以覆盖`findAll()`,提供具体实现。
- **选择性实现**:实现类按需决定是否覆盖该方法。

---

### **3. 为什么抛异常?**
- **明确提示未实现**:如果某个实现类未覆盖`findAll()`,调用时会抛出`UnsupportedOperationException`,避免静默失败。
- **强制开发者注意**:提醒需要此功能的实现类必须覆盖该方法(否则运行时崩溃)。

---

### **4. 实际场景**
#### **场景1:旧实现类(不关心`findAll`)**
```java
@Repository
public class BookDaoImpl implements BookDao {
    @Override
    public Book findById(Long id) { /* 原有逻辑 */ }
    
    // 不覆盖findAll(),沿用接口的默认实现(抛异常)
}
```
- **调用`findAll()`时**:直接崩溃,提示方法未实现。

#### **场景2:新实现类(需要`findAll`)**
```java
@Repository
public class BookDaoJdbcImpl implements BookDao {
    @Override
    public Book findById(Long id) { /* 原有逻辑 */ }
    
    @Override
    public List<Book> findAll() { /* 新增查询逻辑 */ }
}
```
- **调用`findAll()`时**:正常执行。

---

### **5. 与Spring框架的关系**
- **依赖注入无影响**:Spring根据接口类型注入Bean,不关心默认方法。
- **运行时行为**:
  - 若实现类未覆盖默认方法,调用时会抛异常。
  - 若实现类覆盖了默认方法,调用其具体实现。

---

### **6. 设计建议**
- **谨慎使用默认方法**:适合用于接口的渐进式扩展,而非核心方法。
- **文档说明**:在接口中明确标注哪些默认方法需要实现类覆盖。
- **替代方案**:若方法必须被实现,应定义为抽象方法(无默认实现)。

---

### **总结**
这段代码通过**默认方法 + 抛异常**的方式:
1. **保持接口的向后兼容性**,允许逐步扩展功能。
2. **强制提示开发者**:未实现的方法会导致运行时异常,避免隐蔽的错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值