From 1ddbb74e3f0b2e1ec138e02831aa07e686281b9f Mon Sep 17 00:00:00 2001 From: Sergey Penkovsky Date: Thu, 22 Apr 2021 17:30:32 +0300 Subject: [PATCH] added documentation --- README.md | 3 + doc/quick_start_en.md | 0 doc/quick_start_ru.md | 195 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 doc/quick_start_en.md create mode 100644 doc/quick_start_ru.md diff --git a/README.md b/README.md index 7c9e048..6d70669 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ Экспериментальная разработка DI на ЯП Dart +- [New Api ENG](/doc/quick_start_en.md) +- [New Api RU](/doc/quick_start_ru.md) + ## Документация ### Быстрый старт diff --git a/doc/quick_start_en.md b/doc/quick_start_en.md new file mode 100644 index 0000000..e69de29 diff --git a/doc/quick_start_ru.md b/doc/quick_start_ru.md new file mode 100644 index 0000000..85da279 --- /dev/null +++ b/doc/quick_start_ru.md @@ -0,0 +1,195 @@ +# Быстрый старт + +## Основные компоненты DI + + +### Binding + +Binding - по сути это конфигуратор для пользовательского instance, который соддержит методы для конфигурирования зависимости. + +Есть два основных метода для инициализации пользовательского instance `toInstance()` и `toProvide()` и вспомогательных `withName()` и `singeltone()`. + +`toInstance()` - принимает готовый экземпляр + +`toProvide()` -  принимает функцию `provider` (конструктор экземпляра) + +`withName()` - принимает строку для именования экземпляра. По этому имени можно будет извлечь instance из DI контейнера + +`singeltone()` - устанавливает флаг в Binding, который говорит DI контейнеру, что зависимость одна. По этому имени можно будет извлечь instance из DI контейнера. Об + +Пример: + +```dart + // инициализация экземпляра текстовой строки через метод toInstance() + Binding().toInstance("hello world"); + + // или + + // инициализация экземпляра текстовой строки + Binding().toProvide(() => "hello world"); + + // инициализация экземпляра строки с именем + Binding().withName("my_string").toInstance("hello world"); + // или + Binding().withName("my_string").toProvide(() => "hello world"); + + // инициализация экземпляра, как сингелтон + Binding().toInstance("hello world"); + // или + Binding().toProvide(() => "hello world").singeltone(); + +``` + +### Module + +Module - это контейнер пользовательских instances, и на основе которого пользователь может создавать свои модули. Пользователь в своем модуле должен реализовать метод `void builder(Scope currentScope)`. + + +Пример: + +```dart +class AppModule extends Module { + @override + void builder(Scope currentScope) { + bind().toInstance(ApiClientMock()); + } +} +``` + +### Scope + +Scope - это контейнер, который хранит все дерево зависимостей (scope,modules,instances). +Через scope можно получить доступ к `instance`, для этого нужно вызвать метод `resolve()` и указать тип объекта, а так же можно передать дополнительные параметры. + +Пример: + +```dart + // открыть главный scope + final rootScope = DartDi.openRootScope(); + + // инициализация scope пользовательским модулем + rootScope.installModules([AppModule()]); + + // получаем экземпляр класса + final str = rootScope.resolve(); + // или + final str = rootScope.tryResolve(); + + // закрыть главный scope + DartDi.closeRootScope(); +``` + +## Пример приложения + + +```dart +import 'dart:async'; +import 'package:meta/meta.dart'; +import 'package:dart_di/experimental/scope.dart'; +import 'package:dart_di/experimental/module.dart'; + +class AppModule extends Module { + @override + void builder(Scope currentScope) { + bind().withName("apiClientMock").toInstance(ApiClientMock()); + bind().withName("apiClientImpl").toInstance(ApiClientImpl()); + } +} + +class FeatureModule extends Module { + bool isMock; + + FeatureModule({required this.isMock}); + + @override + void builder(Scope currentScope) { + bind() + .withName("networkRepo") + .toProvide( + () => NetworkDataRepository( + currentScope.resolve( + named: isMock ? "apiClientMock" : "apiClientImpl", + ), + ), + ) + .singeltone(); + bind().toProvide( + () => DataBloc( + currentScope.resolve(named: "networkRepo"), + ), + ); + } +} + +void main() async { + final scope = openRootScope().installModules([ + AppModule(), + ]); + + final subScope = scope + .openSubScope("featureScope") + .installModules([FeatureModule(isMock: true)]); + + final dataBloc = subScope.resolve(); + 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 get data => _dataController.stream; + StreamController _dataController = new StreamController.broadcast(); + + DataBloc(this._dataRepository); + + Future fetchData() async { + try { + _dataController.sink.add(await _dataRepository.getData()); + } catch (e) { + _dataController.sink.addError(e); + } + } + + void dispose() { + _dataController.close(); + } +} + +abstract class DataRepository { + Future getData(); +} + +class NetworkDataRepository implements DataRepository { + final ApiClient _apiClient; + final _token = 'token'; + + NetworkDataRepository(this._apiClient); + + @override + Future 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'; + } +} +``` \ No newline at end of file