# Clean Architecture ## 目录 - [Clean Architecture概念](#clean-architecture概念) - [分层架构](#分层架构) - [依赖规则](#依赖规则) - [领域层](#领域层) - [数据层](#数据层) - [表现层](#表现层) - [Clean Architecture实现](#clean-architecture实现) - [Clean Architecture最佳实践](#clean-architecture最佳实践) - [面试常见问题](#面试常见问题) --- ## Clean Architecture概念 ### 什么是 Clean Architecture? Clean Architecture(整洁架构)是由 Robert C. Martin 提出的一种软件架构设计理念,强调: 1. **独立性**:框架、UI、数据库、外部服务都是可替换的 2. **可测试性**:业务逻辑可以独立测试 3. **独立性**:业务逻辑不依赖外部框架 4. **可维护性**:代码结构清晰,易于维护 ### Clean Architecture 架构图 ``` ┌─────────────────────────────────────┐ │ Presentation Layer │ ← 表现层(UI、ViewModel) │ (Activities, Fragments, ViewModels) │ └──────────────┬──────────────────────┘ │ ┌──────────────▼──────────────────────┐ │ Domain Layer │ ← 领域层(业务逻辑) │ (Use Cases, Entities, Interfaces) │ └──────────────┬──────────────────────┘ │ ┌──────────────▼──────────────────────┐ │ Data Layer │ ← 数据层(Repository 实现) │ (Repositories, Data Sources, API) │ └─────────────────────────────────────┘ ``` ### Clean Architecture 核心原则 1. **依赖倒置**:依赖方向由外向内 2. **单一职责**:每个类只有一个职责 3. **开闭原则**:对扩展开放,对修改关闭 4. **接口隔离**:使用接口隔离依赖 --- ## 分层架构 ### 三层架构 #### 1. 表现层(Presentation Layer) **职责:** - 显示 UI - 处理用户输入 - 调用 Use Case **组件:** - Activities - Fragments - ViewModels - Adapters #### 2. 领域层(Domain Layer) **职责:** - 业务逻辑 - 业务规则 - 实体定义 **组件:** - Entities(实体) - Use Cases(用例) - Repository Interfaces(仓库接口) #### 3. 数据层(Data Layer) **职责:** - 数据获取 - 数据存储 - Repository 实现 **组件:** - Repository Implementations - Data Sources(API、Database、Cache) - Data Models ### 依赖方向 ``` 表现层 → 领域层 → 数据层 ``` - 表现层依赖领域层 - 领域层不依赖表现层和数据层 - 数据层实现领域层的接口 --- ## 依赖规则 ### 依赖倒置原则 ```java // ✅ 正确:领域层定义接口,数据层实现接口 // Domain Layer public interface UserRepository { Single> getUsers(); } // Data Layer public class UserRepositoryImpl implements UserRepository { @Override public Single> getUsers() { // 实现 } } // ❌ 错误:领域层依赖数据层 // Domain Layer public class UserUseCase { private UserRepositoryImpl repository; // 依赖具体实现 } ``` ### 依赖方向 ``` ┌─────────────┐ │ Presentation │ └──────┬───────┘ │ 依赖 ↓ ┌─────────────┐ │ Domain │ ← 核心层,不依赖其他层 └──────┬───────┘ │ 接口 ↑ 实现 ┌─────────────┐ │ Data │ └─────────────┘ ``` --- ## 领域层 ### Entity(实体) ```java // Domain Layer: Entity public class User { private String id; private String name; private String email; public User(String id, String name, String email) { this.id = id; this.name = name; this.email = email; } // Getters public String getId() { return id; } public String getName() { return name; } public String getEmail() { return email; } // 业务逻辑 public boolean isValid() { return name != null && !name.isEmpty() && email != null && email.contains("@"); } } ``` ### Use Case(用例) ```java // Domain Layer: Use Case public class GetUsersUseCase { private UserRepository repository; public GetUsersUseCase(UserRepository repository) { this.repository = repository; } public Single> execute() { return repository.getUsers() .map(users -> { // 业务逻辑处理 return users.stream() .filter(User::isValid) .collect(Collectors.toList()); }); } } public class AddUserUseCase { private UserRepository repository; public AddUserUseCase(UserRepository repository) { this.repository = repository; } public Completable execute(User user) { if (!user.isValid()) { return Completable.error(new IllegalArgumentException("Invalid user")); } return repository.addUser(user); } } ``` ### Repository Interface(仓库接口) ```java // Domain Layer: Repository Interface public interface UserRepository { Single> getUsers(); Single getUserById(String id); Completable addUser(User user); Completable updateUser(User user); Completable deleteUser(String id); } ``` --- ## 数据层 ### Repository Implementation(仓库实现) ```java // Data Layer: Repository Implementation public class UserRepositoryImpl implements UserRepository { private UserRemoteDataSource remoteDataSource; private UserLocalDataSource localDataSource; public UserRepositoryImpl( UserRemoteDataSource remoteDataSource, UserLocalDataSource localDataSource ) { this.remoteDataSource = remoteDataSource; this.localDataSource = localDataSource; } @Override public Single> getUsers() { return remoteDataSource.getUsers() .doOnSuccess(localDataSource::saveUsers) .onErrorResumeNext(localDataSource.getUsers()); } @Override public Single getUserById(String id) { return localDataSource.getUserById(id) .onErrorResumeNext(remoteDataSource.getUserById(id)); } @Override public Completable addUser(User user) { return remoteDataSource.addUser(user) .andThen(localDataSource.saveUser(user)); } @Override public Completable updateUser(User user) { return remoteDataSource.updateUser(user) .andThen(localDataSource.updateUser(user)); } @Override public Completable deleteUser(String id) { return remoteDataSource.deleteUser(id) .andThen(localDataSource.deleteUser(id)); } } ``` ### Data Source(数据源) ```java // Data Layer: Remote Data Source public class UserRemoteDataSource { private ApiService apiService; public UserRemoteDataSource(ApiService apiService) { this.apiService = apiService; } public Single> getUsers() { return apiService.getUsers() .map(userResponses -> { return userResponses.stream() .map(this::mapToUser) .collect(Collectors.toList()); }); } private User mapToUser(UserResponse response) { return new User( response.getId(), response.getName(), response.getEmail() ); } } // Data Layer: Local Data Source public class UserLocalDataSource { private UserDao userDao; public UserLocalDataSource(UserDao userDao) { this.userDao = userDao; } public Single> getUsers() { return userDao.getUsers() .map(userEntities -> { return userEntities.stream() .map(this::mapToUser) .collect(Collectors.toList()); }); } public void saveUsers(List users) { List entities = users.stream() .map(this::mapToEntity) .collect(Collectors.toList()); userDao.insertUsers(entities); } private User mapToUser(UserEntity entity) { return new User( entity.getId(), entity.getName(), entity.getEmail() ); } private UserEntity mapToEntity(User user) { UserEntity entity = new UserEntity(); entity.setId(user.getId()); entity.setName(user.getName()); entity.setEmail(user.getEmail()); return entity; } } ``` --- ## 表现层 ### ViewModel ```java // Presentation Layer: ViewModel public class UserViewModel extends ViewModel { private GetUsersUseCase getUsersUseCase; private AddUserUseCase addUserUseCase; private MutableLiveData> users = new MutableLiveData<>(); private MutableLiveData error = new MutableLiveData<>(); private MutableLiveData loading = new MutableLiveData<>(); public UserViewModel( GetUsersUseCase getUsersUseCase, AddUserUseCase addUserUseCase ) { this.getUsersUseCase = getUsersUseCase; this.addUserUseCase = addUserUseCase; } public LiveData> getUsers() { return users; } public LiveData getError() { return error; } public LiveData getLoading() { return loading; } public void loadUsers() { loading.setValue(true); getUsersUseCase.execute() .observeOn(AndroidSchedulers.mainThread()) .subscribe( userList -> { loading.setValue(false); users.setValue(userList); }, throwable -> { loading.setValue(false); error.setValue(throwable.getMessage()); } ); } public void addUser(String name, String email) { loading.setValue(true); User user = new User(UUID.randomUUID().toString(), name, email); addUserUseCase.execute(user) .observeOn(AndroidSchedulers.mainThread()) .subscribe( () -> { loading.setValue(false); loadUsers(); }, throwable -> { loading.setValue(false); error.setValue(throwable.getMessage()); } ); } } ``` ### Activity/Fragment ```java // Presentation Layer: Activity public class UserActivity extends AppCompatActivity { private UserViewModel viewModel; private ActivityUserBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = DataBindingUtil.setContentView(this, R.layout.activity_user); // 依赖注入 UserRepository repository = new UserRepositoryImpl( new UserRemoteDataSource(createApiService()), new UserLocalDataSource(createUserDao()) ); GetUsersUseCase getUsersUseCase = new GetUsersUseCase(repository); AddUserUseCase addUserUseCase = new AddUserUseCase(repository); viewModel = ViewModelProviders.of(this, new ViewModelFactory( getUsersUseCase, addUserUseCase )).get(UserViewModel.class); binding.setViewModel(viewModel); binding.setLifecycleOwner(this); observeViewModel(); } private void observeViewModel() { viewModel.getUsers().observe(this, users -> { adapter.updateUsers(users); }); viewModel.getError().observe(this, error -> { Toast.makeText(this, error, Toast.LENGTH_SHORT).show(); }); } } ``` --- ## Clean Architecture实现 ### 项目结构 ``` app/ ├── presentation/ # 表现层 │ ├── ui/ │ │ ├── activities/ │ │ ├── fragments/ │ │ └── adapters/ │ └── viewmodels/ ├── domain/ # 领域层 │ ├── entities/ │ ├── usecases/ │ └── repositories/ └── data/ # 数据层 ├── repositories/ ├── datasources/ │ ├── remote/ │ └── local/ └── models/ ``` ### 依赖配置 ```gradle // app/build.gradle dependencies { // 表现层依赖领域层 implementation project(':domain') // 表现层依赖数据层(用于依赖注入) implementation project(':data') } // domain/build.gradle dependencies { // 领域层不依赖其他层,只依赖 RxJava 等工具库 implementation 'io.reactivex.rxjava2:rxjava:2.2.19' } // data/build.gradle dependencies { // 数据层依赖领域层(实现接口) implementation project(':domain') // 数据层依赖第三方库 implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'androidx.room:room-runtime:2.3.0' } ``` --- ## Clean Architecture最佳实践 ### 1. 依赖倒置 ```java // ✅ 正确:领域层定义接口 // Domain Layer public interface UserRepository { Single> getUsers(); } // Data Layer 实现接口 public class UserRepositoryImpl implements UserRepository { // 实现 } // ❌ 错误:领域层依赖数据层 // Domain Layer public class UserUseCase { private UserRepositoryImpl repository; // 依赖具体实现 } ``` ### 2. 单一职责 ```java // ✅ 正确:每个类只有一个职责 public class GetUsersUseCase { public Single> execute() { // 只负责获取用户列表 } } public class AddUserUseCase { public Completable execute(User user) { // 只负责添加用户 } } // ❌ 错误:一个类承担多个职责 public class UserUseCase { public void getUsers() { } public void addUser() { } public void updateUser() { } public void deleteUser() { } } ``` ### 3. 接口隔离 ```java // ✅ 正确:接口职责单一 public interface UserRepository { Single> getUsers(); Single getUserById(String id); } // ❌ 错误:接口职责过多 public interface UserRepository { void getUsers(); void addUser(); void updateUser(); void deleteUser(); void uploadFile(); void downloadFile(); } ``` ### 4. 测试 ```java // 领域层可以独立测试 public class GetUsersUseCaseTest { @Test public void testExecute() { UserRepository mockRepository = mock(UserRepository.class); when(mockRepository.getUsers()).thenReturn(Single.just(users)); GetUsersUseCase useCase = new GetUsersUseCase(mockRepository); useCase.execute() .test() .assertValue(users); } } ``` --- ## 面试常见问题 ### Q1: 什么是 Clean Architecture? **答案:** Clean Architecture(整洁架构)是由 Robert C. Martin 提出的一种软件架构设计理念,强调: 1. 独立性:框架、UI、数据库都是可替换的 2. 可测试性:业务逻辑可以独立测试 3. 独立性:业务逻辑不依赖外部框架 4. 可维护性:代码结构清晰,易于维护 ### Q2: Clean Architecture 的分层? **答案:** 1. **表现层**:UI、ViewModel、Activities、Fragments 2. **领域层**:Entities、Use Cases、Repository Interfaces 3. **数据层**:Repository Implementations、Data Sources ### Q3: Clean Architecture 的依赖规则? **答案:** 1. **依赖倒置**:领域层定义接口,数据层实现接口 2. **依赖方向**:表现层 → 领域层 → 数据层 3. **领域层独立**:领域层不依赖其他层 ### Q4: Use Case 的作用? **答案:** Use Case(用例)封装了特定的业务逻辑,每个 Use Case 只负责一个业务功能,使业务逻辑清晰、可测试、可复用。 ### Q5: Repository 模式的作用? **答案:** Repository 模式封装了数据访问逻辑,提供统一的数据访问接口,隐藏了数据来源(网络、数据库、缓存)的细节。 ### Q6: Clean Architecture 的优势? **答案:** 1. 可测试性:业务逻辑可以独立测试 2. 可维护性:代码结构清晰 3. 可扩展性:易于添加新功能 4. 独立性:不依赖外部框架 --- ## 总结 Clean Architecture 是一种优秀的软件架构设计理念,通过分层架构和依赖倒置,实现了业务逻辑的独立性和可测试性。在实际项目中,需要合理划分层次、定义接口、实现依赖倒置。 --- *最后更新:2024年*