场景1:没有依赖倒置的耦合代码
1. 定义具体的消息服务类
export default class EmailService { send(to, message) { console.log(`Sending email to ${to}: ${message}`); } }
export default class SMSService { send(to, message) { console.log(`Sending SMS to ${to}: ${message}`); } }
|
2. 在组件中直接依赖具体的服务
<template> <div> <button @click="sendNotification">Send Notification</button> </div> </template>
<script setup>
import EmailService from '../services/EmailService';
const emailService = new EmailService();
const sendNotification = () => { emailService.send('user@example.com', 'Hello without Dependency Inversion!'); }; </script>
|
场景1结论
假设你想从 EmailService 切换到 SMSService,你需要在组件代码中手动进行以下修改:
- 修改 import 语句,切换到新的服务类。
- 修改实例化代码,使用新的服务类创建实例。
- 修改所有调用代码,确保使用新的服务实例发送消息。
场景2:使用依赖倒置解耦合代码
1. 定义 MessageService 抽象接口
export default class MessageService { send(to, message) { throw new Error('This method should be overridden'); } }
|
2. 定义具体的消息服务类
import MessageService from './MessageService';
export default class EmailService extends MessageService { send(to, message) { console.log(`Sending email to ${to}: ${message}`); } }
import MessageService from './MessageService';
export default class SMSService extends MessageService { send(to, message) { console.log(`Sending SMS to ${to}: ${message}`); } }
|
3. 在页面中提供消息服务
<template> <div> <NotificationComponent /> </div> </template>
<script setup> import { provide } from 'vue'; import EmailService from './services/EmailService';
const messageService = new EmailService();
provide('messageService', messageService); </script>
|
4. 创建消息服务的组件
<template> <div> <button @click="sendNotification">Send Notification</button> </div> </template>
<script setup> import { inject } from 'vue';
const messageService = inject('messageService');
const sendNotification = () => { messageService.send('user@example.com', 'Hello via Vue 3 and Dependency Inversion!'); }; </script>
|
场景2结论
解耦: 组件和服务实现之间是解耦的,组件只关心 MessageService 抽象接口,而不关心具体的实现。
灵活性: 可以轻松替换不同的服务实现而无需修改组件代码。
可测试性: 组件依赖于抽象接口,可以轻松地在测试中替换为模拟实现。
依赖倒置的核心思想是:"高层模块不应该依赖于低层模块,而是应该依赖于抽象接口"。