← Назад к вопросам

Зачем нужны архитектурные слои в Flutter?

1.3 Junior🔥 151 комментариев
#Архитектура Flutter

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ответ

Архитектурные слои в Flutter — это структурное разделение приложения на отдельные уровни абстракции, каждый из которых отвечает за конкретную функциональность. Классическая архитектура включает слои: presentation, domain, application и infrastructure. Это критически важно для создания масштабируемых, поддерживаемых и тестируемых приложений.

Основные проблемы без архитектурных слоёв

// Плохо — всё смешано в одном месте
class UserProfilePage extends StatefulWidget {
  @override
  State<UserProfilePage> createState() => _UserProfilePageState();
}

class _UserProfilePageState extends State<UserProfilePage> {
  late User user;

  @override
  void initState() {
    super.initState();
    // Бизнес-логика прямо в UI
    final dio = Dio();
    dio.get("/api/users/me").then((response) {
      final db = Database();
      final user = User.fromJson(response.data);
      db.save(user); // сохранение в БД тут же
      setState(() => this.user = user);
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Text(user.name),
    );
  }
}

Классическая многослойная архитектура

┌─────────────────────────────────────┐
│     Presentation Layer (UI)        │
│  Виджеты, экраны, управление      │
└────────────────┬────────────────────┘
                 │ зависит от
┌─────────────────▼────────────────────┐
│  Application Layer (UseCase)         │
│  Бизнес-логика, часто используемые │
│  операции, состояние приложения    │
└────────────────┬────────────────────┘
                 │ зависит от
┌─────────────────▼────────────────────┐
│    Domain Layer (Entity, Interface)  │
│  Чистая бизнес-логика, модели,     │
│  интерфейсы репозиториев            │
└────────────────┬────────────────────┘
                 │ зависит от
┌─────────────────▼────────────────────┐
│  Infrastructure Layer (реализация)   │
│  Сеть, БД, внешние сервисы          │
└─────────────────────────────────────┘

Паттерн Clean Architecture

// Domain слой — не зависит ни от чего
class User {
  final String id;
  final String name;
  final String email;

  User({required this.id, required this.name, required this.email});
}

abstract class UserRepository {
  Future<User> getUserById(String id);
  Future<void> saveUser(User user);
}

// Application слой — содержит use cases
class GetUserUseCase {
  final UserRepository repository;

  GetUserUseCase(this.repository);

  Future<User> execute(String userId) {
    return repository.getUserById(userId);
  }
}

// Infrastructure слой — конкретная реализация
class UserRepositoryImpl implements UserRepository {
  final Dio httpClient;
  final LocalDatabase database;

  UserRepositoryImpl(this.httpClient, this.database);

  @override
  Future<User> getUserById(String id) async {
    try {
      final response = await httpClient.get("/api/users/$id");
      final user = User.fromJson(response.data);
      await database.saveUser(user);
      return user;
    } catch (e) {
      return database.getUserById(id);
    }
  }

  @override
  Future<void> saveUser(User user) => database.saveUser(user);
}

// Presentation слой — только UI логика
class UserProfilePage extends ConsumerWidget {
  final String userId;

  const UserProfilePage({required this.userId});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final userAsyncValue = ref.watch(getUserProvider(userId));

    return userAsyncValue.when(
      data: (user) => Scaffold(
        body: Text(user.name),
      ),
      loading: () => const CircularProgressIndicator(),
      error: (error, _) => Text("Error: $error"),
    );
  }
}

Преимущества архитектурных слоёв

Разделение ответственности — каждый слой знает только о своей зоне:

// UI слой не знает об HTTP и БД
class Button extends StatelessWidget {
  final String label;
  final VoidCallback onPressed;

  const Button({required this.label, required this.onPressed});

  @override
  Widget build(BuildContext context) => TextButton(
    onPressed: onPressed,
    child: Text(label),
  );
}

Тестируемость — легко писать unit тесты:

void main() {
  group("GetUserUseCase", () {
    test("returns user from repository", () async {
      final mockRepo = MockUserRepository();
      when(mockRepo.getUserById("123"))
          .thenAnswer((_) async => User(id: "123", name: "John", email: "john@example.com"));

      final useCase = GetUserUseCase(mockRepo);
      final result = await useCase.execute("123");

      expect(result.name, "John");
    });
  });
}

Масштабируемость — просто добавлять новую функциональность.

Переиспользуемость — один use case может использоваться разными экранами.

Гибкость — легко менять реализацию без изменения других слоёв.

Архитектурные слои — это не усложнение, а инвестиция в качество и долговечность кода.