Files
mkdocs/docs/android面试/系统架构/Clean_Architecture.md
2026-01-15 11:53:37 +08:00

671 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 SourcesAPI、Database、Cache
- Data Models
### 依赖方向
```
表现层 → 领域层 → 数据层
```
- 表现层依赖领域层
- 领域层不依赖表现层和数据层
- 数据层实现领域层的接口
---
## 依赖规则
### 依赖倒置原则
```java
// ✅ 正确:领域层定义接口,数据层实现接口
// Domain Layer
public interface UserRepository {
Single<List<User>> getUsers();
}
// Data Layer
public class UserRepositoryImpl implements UserRepository {
@Override
public Single<List<User>> 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<List<User>> 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<List<User>> getUsers();
Single<User> 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<List<User>> getUsers() {
return remoteDataSource.getUsers()
.doOnSuccess(localDataSource::saveUsers)
.onErrorResumeNext(localDataSource.getUsers());
}
@Override
public Single<User> 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<List<User>> 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<List<User>> getUsers() {
return userDao.getUsers()
.map(userEntities -> {
return userEntities.stream()
.map(this::mapToUser)
.collect(Collectors.toList());
});
}
public void saveUsers(List<User> users) {
List<UserEntity> 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<List<User>> users = new MutableLiveData<>();
private MutableLiveData<String> error = new MutableLiveData<>();
private MutableLiveData<Boolean> loading = new MutableLiveData<>();
public UserViewModel(
GetUsersUseCase getUsersUseCase,
AddUserUseCase addUserUseCase
) {
this.getUsersUseCase = getUsersUseCase;
this.addUserUseCase = addUserUseCase;
}
public LiveData<List<User>> getUsers() {
return users;
}
public LiveData<String> getError() {
return error;
}
public LiveData<Boolean> 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<List<User>> getUsers();
}
// Data Layer 实现接口
public class UserRepositoryImpl implements UserRepository {
// 实现
}
// ❌ 错误:领域层依赖数据层
// Domain Layer
public class UserUseCase {
private UserRepositoryImpl repository; // 依赖具体实现
}
```
### 2. 单一职责
```java
// ✅ 正确:每个类只有一个职责
public class GetUsersUseCase {
public Single<List<User>> 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<List<User>> getUsers();
Single<User> 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年*