Files
cherrypick/doc/quick_start_ru.md
Sergey Penkovsky aa97632add feat(logger): add extensible logging API, usage examples, and bilingual documentation
- Introduce CherryPickLogger interface, PrintLogger and SilentLogger implementations
- Add setGlobalLogger() to CherryPick API for custom DI logging
- Log key events (scope, module, error) via logger throughout DI lifecycle
- Comprehensive comments and code documentation in both English and Russian
- Document usage of logging system in quick_start and full_tutorial documentation (EN/RU)
- Provide usage examples in docs and code comments
- No logging inside GlobalCycleDetectionMixin (design choice: exceptions handled at Scope, not detector/mixin level) and detailed architectural reasoning
- Update helper.dart, logger.dart: comments, examples, API doc improvements
BREAKING CHANGE: Projects can now inject any logger via CherryPick.setGlobalLogger; default log behavior clarified and docstrings/usage examples enhanced
2025-08-08 08:24:13 +03:00

213 lines
6.7 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.

# Быстрый старт
## Основные компоненты DI
### Binding
Binding - по сути это конфигуратор для пользовательского instance, который соддержит методы для конфигурирования зависимости.
Есть два основных метода для инициализации пользовательского instance `toInstance()` и `toProvide()` и вспомогательных `withName()` и `singleton()`.
`toInstance()` - принимает готовый экземпляр
`toProvide()` -  принимает функцию `provider` (конструктор экземпляра)
`withName()` - принимает строку для именования экземпляра. По этому имени можно будет извлечь instance из DI контейнера
`singleton()` - устанавливает флаг в Binding, который говорит DI контейнеру, что зависимость одна.
Пример:
```dart
// инициализация экземпляра текстовой строки через метод toInstance()
Binding<String>().toInstance("hello world");
// или
// инициализация экземпляра текстовой строки
Binding<String>().toProvide(() => "hello world");
// инициализация экземпляра строки с именем
Binding<String>().withName("my_string").toInstance("hello world");
// или
Binding<String>().withName("my_string").toProvide(() => "hello world");
// инициализация экземпляра, как сингелтон
Binding<String>().toInstance("hello world");
// или
Binding<String>().toProvide(() => "hello world").singleton();
```
### Module
Module - это контейнер пользовательских instances, и на основе которого пользователь может создавать свои модули. Пользователь в своем модуле должен реализовать метод `void builder(Scope currentScope)`.
Пример:
```dart
class AppModule extends Module {
@override
void builder(Scope currentScope) {
bind<ApiClient>().toInstance(ApiClientMock());
}
}
```
### Scope
Scope - это контейнер, который хранит все дерево зависимостей (scope,modules,instances).
Через scope можно получить доступ к `instance`, для этого нужно вызвать метод `resolve<T>()` и указать тип объекта, а так же можно передать дополнительные параметры.
Пример:
```dart
// открыть главный scope
final rootScope = CherryPick.openRootScope();
// инициализация scope пользовательским модулем
rootScope.installModules([AppModule()]);
// получаем экземпляр класса
final str = rootScope.resolve<String>();
// или
final str = rootScope.tryResolve<String>();
// закрыть главный scope
Cherrypick.closeRootScope();
```
## Логирование
Чтобы включить вывод логов о событиях и ошибках DI в CherryPick, настройте глобальный логгер до создания любых scope:
```dart
import 'package:cherrypick/cherrypick.dart';
void main() {
// Установите глобальный логгер до создания scope
CherryPick.setGlobalLogger(PrintLogger()); // или свой логгер
final scope = CherryPick.openRootScope();
// Логи DI и циклов будут выводиться через ваш логгер
}
```
- По умолчанию используется SilentLogger (нет логов в продакшене).
- Любые ошибки резолва и события циклов логируются через info/error на логгере.
## Пример приложения
```dart
import 'dart:async';
import 'package:meta/meta.dart';
import 'package:cherrypick/cherrypick.dart';
class AppModule extends Module {
@override
void builder(Scope currentScope) {
bind<ApiClient>().withName("apiClientMock").toInstance(ApiClientMock());
bind<ApiClient>().withName("apiClientImpl").toInstance(ApiClientImpl());
}
}
class FeatureModule extends Module {
bool isMock;
FeatureModule({required this.isMock});
@override
void builder(Scope currentScope) {
bind<DataRepository>()
.withName("networkRepo")
.toProvide(
() => NetworkDataRepository(
currentScope.resolve<ApiClient>(
named: isMock ? "apiClientMock" : "apiClientImpl",
),
),
)
.singleton();
bind<DataBloc>().toProvide(
() => DataBloc(
currentScope.resolve<DataRepository>(named: "networkRepo"),
),
);
}
}
void main() async {
final scope = openRootScope().installModules([
AppModule(),
]);
final subScope = scope
.openSubScope("featureScope")
.installModules([FeatureModule(isMock: true)]);
final dataBloc = subScope.resolve<DataBloc>();
dataBloc.data.listen((d) => print('Received data: $d'),
onError: (e) => print('Error: $e'), onDone: () => print('DONE'));
await dataBloc.fetchData();
}
class DataBloc {
final DataRepository _dataRepository;
Stream<String> get data => _dataController.stream;
StreamController<String> _dataController = new StreamController.broadcast();
DataBloc(this._dataRepository);
Future<void> fetchData() async {
try {
_dataController.sink.add(await _dataRepository.getData());
} catch (e) {
_dataController.sink.addError(e);
}
}
void dispose() {
_dataController.close();
}
}
abstract class DataRepository {
Future<String> getData();
}
class NetworkDataRepository implements DataRepository {
final ApiClient _apiClient;
final _token = 'token';
NetworkDataRepository(this._apiClient);
@override
Future<String> getData() async => await _apiClient.sendRequest(
url: 'www.google.com', token: _token, requestBody: {'type': 'data'});
}
abstract class ApiClient {
Future sendRequest({@required String url, String token, Map requestBody});
}
class ApiClientMock implements ApiClient {
@override
Future sendRequest(
{@required String? url, String? token, Map? requestBody}) async {
return 'Local Data';
}
}
class ApiClientImpl implements ApiClient {
@override
Future sendRequest(
{@required String? url, String? token, Map? requestBody}) async {
return 'Network data';
}
}
```