基于Clean Architecture的Vue 3项目分层设计实践

基于Clean Architecture的Vue 3项目分层设计实践

开场白

大家好,欢迎来到今天的讲座!今天我们要聊的是一个非常有趣的话题:如何在Vue 3项目中应用Clean Architecture。如果你对“架构”这个词感到头疼,别担心,我会尽量用轻松诙谐的语言来解释这些概念,让你在愉快的氛围中掌握它们。

首先,什么是Clean Architecture?简单来说,它是一种分层架构模式,旨在将业务逻辑与技术细节分离,使得代码更加模块化、可维护和可测试。Clean Architecture的核心思想是“依赖倒置原则”,即高层次模块不应该依赖于低层次模块,而是通过抽象接口进行通信。

那么,为什么我们需要在Vue 3项目中引入Clean Architecture呢?原因很简单:随着项目的规模越来越大,代码的复杂度也会增加。如果没有一个好的架构设计,项目很容易变成一团乱麻,难以维护和扩展。而Clean Architecture可以帮助我们避免这些问题,让代码更加清晰、易于理解和测试。

接下来,我们将通过一个具体的例子来讲解如何在Vue 3项目中实现Clean Architecture。假设我们要开发一个简单的任务管理应用,用户可以添加、编辑和删除任务。我们将把这个应用分为四个主要层次:

  1. UI层(Presentation Layer):负责与用户交互,展示数据。
  2. 应用层(Application Layer):处理业务逻辑,协调不同模块之间的交互。
  3. 领域层(Domain Layer):包含核心业务规则和实体。
  4. 基础设施层(Infrastructure Layer):提供外部服务(如API、数据库等)的实现。

1. UI层:Vue 3 + Composition API

在Vue 3中,我们使用Composition API来组织代码,它比传统的Options API更加灵活和强大。UI层的主要职责是展示数据并与用户交互,因此我们可以将所有的UI逻辑放在这个层中。

1.1. 创建任务列表组件

<template>
  <div>
    <h1>任务管理</h1>
    <ul>
      <li v-for="task in tasks" :key="task.id">
        {{ task.title }}
        <button @click="deleteTask(task.id)">删除</button>
      </li>
    </ul>
    <input v-model="newTaskTitle" placeholder="新任务" />
    <button @click="addTask">添加任务</button>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { useTaskStore } from '@/stores/taskStore';

const taskStore = useTaskStore();
const tasks = ref([]);
const newTaskTitle = ref('');

onMounted(() => {
  tasks.value = taskStore.getTasks();
});

const addTask = () => {
  if (newTaskTitle.value.trim()) {
    taskStore.addTask(newTaskTitle.value);
    newTaskTitle.value = '';
  }
};

const deleteTask = (id) => {
  taskStore.deleteTask(id);
};
</script>

在这个组件中,我们使用了useTaskStore来获取任务数据,并通过addTaskdeleteTask方法与应用层进行交互。注意,UI层并不直接操作数据,而是通过调用应用层提供的接口来完成任务。

1.2. 使用Pinia进行状态管理

为了更好地管理应用的状态,我们使用Pinia作为状态管理库。Pinia是一个轻量级的状态管理库,专为Vue 3设计,使用起来非常简单。

// src/stores/taskStore.js
import { defineStore } from 'pinia';
import { useTaskRepository } from '@/repositories/TaskRepository';

export const useTaskStore = defineStore('task', {
  state: () => ({
    tasks: [],
  }),
  actions: {
    async getTasks() {
      this.tasks = await useTaskRepository().getTasks();
    },
    async addTask(title) {
      await useTaskRepository().addTask({ title });
      this.getTasks();
    },
    async deleteTask(id) {
      await useTaskRepository().deleteTask(id);
      this.getTasks();
    },
  },
});

在这里,useTaskStore负责管理任务的状态,并通过useTaskRepository与基础设施层进行通信。这样,UI层只需要关注如何展示数据,而不需要关心数据的来源或如何操作数据。

2. 应用层:协调业务逻辑

应用层是Clean Architecture的核心部分,它负责处理业务逻辑并协调不同模块之间的交互。在这个层中,我们定义了与领域层相关的操作,并通过接口与基础设施层进行通信。

2.1. 定义任务接口

为了让应用层与基础设施层解耦,我们首先需要定义一个接口,描述任务相关的操作。这个接口将被应用层调用,而具体的实现则放在基础设施层中。

// src/repositories/ITaskRepository.ts
export interface ITaskRepository {
  getTasks(): Promise<Task[]>;
  addTask(task: Task): Promise<void>;
  deleteTask(id: string): Promise<void>;
}

interface Task {
  id: string;
  title: string;
}

2.2. 实现任务仓库

接下来,我们在基础设施层中实现这个接口。这里我们使用Axios来与后端API进行通信。

// src/repositories/TaskRepository.ts
import axios from 'axios';
import { ITaskRepository, Task } from './ITaskRepository';

class TaskRepository implements ITaskRepository {
  private api = axios.create({
    baseURL: 'https://api.example.com/tasks',
  });

  async getTasks(): Promise<Task[]> {
    const response = await this.api.get('/');
    return response.data;
  }

  async addTask(task: Task): Promise<void> {
    await this.api.post('/', task);
  }

  async deleteTask(id: string): Promise<void> {
    await this.api.delete(`/${id}`);
  }
}

export const useTaskRepository = (): ITaskRepository => new TaskRepository();

通过这种方式,应用层只需要依赖ITaskRepository接口,而不需要知道具体的实现细节。这使得我们可以轻松地更换不同的数据源(例如从API切换到本地存储),而不会影响应用的其他部分。

3. 领域层:核心业务规则

领域层是Clean Architecture中最核心的部分,它包含了业务规则和实体。在这个层中,我们定义了与业务逻辑相关的类和函数,确保它们不依赖于任何外部技术细节。

3.1. 定义任务实体

// src/domain/Task.ts
export class Task {
  constructor(public id: string, public title: string) {}

  static create(title: string): Task {
    return new Task(Date.now().toString(), title);
  }

  validate(): boolean {
    return this.title.length > 0;
  }
}

在这个例子中,Task类包含了任务的基本属性和一些业务规则(例如验证任务标题是否为空)。领域层的代码应该是纯业务逻辑,不涉及任何UI或基础设施的实现。

4. 基础设施层:外部服务实现

基础设施层负责提供外部服务的实现,例如API、数据库、文件系统等。在这个层中,我们实现了ITaskRepository接口,并使用Axios与后端API进行通信。

4.1. 使用Axios与API通信

// src/repositories/TaskRepository.ts
import axios from 'axios';
import { ITaskRepository, Task } from './ITaskRepository';

class TaskRepository implements ITaskRepository {
  private api = axios.create({
    baseURL: 'https://api.example.com/tasks',
  });

  async getTasks(): Promise<Task[]> {
    const response = await this.api.get('/');
    return response.data.map((task: any) => new Task(task.id, task.title));
  }

  async addTask(task: Task): Promise<void> {
    await this.api.post('/', { id: task.id, title: task.title });
  }

  async deleteTask(id: string): Promise<void> {
    await this.api.delete(`/${id}`);
  }
}

export const useTaskRepository = (): ITaskRepository => new TaskRepository();

通过这种方式,基础设施层提供了具体的实现,而应用层和领域层则保持独立,不会受到外部服务的变化影响。

总结

通过今天的讲座,我们学习了如何在Vue 3项目中应用Clean Architecture。Clean Architecture的核心思想是将业务逻辑与技术细节分离,使得代码更加模块化、可维护和可测试。我们通过四个层次(UI层、应用层、领域层和基础设施层)来组织代码,确保每个层次只关注自己的职责,而不依赖于其他层次的具体实现。

希望今天的分享对你有所帮助!如果你有任何问题或想法,欢迎在评论区留言讨论。下次见! 😄


参考资料:

  • Robert C. Martin, Clean Architecture: A Craftsman’s Guide to Software Structure and Design.
  • Vue 3 Documentation, Composition API.
  • Pinia Documentation, State Management for Vue 3.
  • Axios Documentation, Promise based HTTP client for the browser and node.js.

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注