refactored code

This commit is contained in:
Sergey Penkovsky
2021-10-20 09:15:51 +03:00
parent 4cb210d0c2
commit c49c9012ac
11 changed files with 17 additions and 21 deletions

120
lib/src/binding.dart Normal file
View File

@@ -0,0 +1,120 @@
///
/// Copyright 2021 Sergey Penkovsky <sergey.penkovsky@gmail.com>
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
/// http://www.apache.org/licenses/LICENSE-2.0
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
enum Mode { SIMPLE, INSTANCE, PROVIDER_INSTANCE }
/// RU: Класс Binding<T> настраивает параметры экземпляра.
/// ENG: The Binding<T> class configures the settings for the instance.
///
class Binding<T> {
late Mode _mode;
late Type _key;
late String _name;
T? _instance;
T? Function()? _provider;
late bool _isSingeltone = false;
late bool _isNamed = false;
Binding() {
_mode = Mode.SIMPLE;
_key = T;
}
/// RU: Метод возвращает [Mode] экземпляра.
/// ENG: The method returns the [Mode] of the instance.
///
/// return [Mode]
Mode get mode => _mode;
/// RU: Метод возвращает тип экземпляра.
/// ENG: The method returns the type of the instance.
///
/// return [Type]
Type get key => _key;
/// RU: Метод возвращает имя экземпляра.
/// ENG: The method returns the name of the instance.
///
/// return [String]
String get name => _name;
/// RU: Метод проверяет сингелтон экземпляр или нет.
/// ENG: The method checks the singleton instance or not.
///
/// return [bool]
bool get isSingeltone => _isSingeltone;
/// RU: Метод проверяет именован экземпляр или нет.
/// ENG: The method checks whether the instance is named or not.
///
/// return [bool]
bool get isNamed => _isNamed;
/// RU: Добавляет имя для экземляпя [value].
/// ENG: Added name for instance [value].
///
/// return [Binding]
Binding<T> withName(String name) {
_name = name;
_isNamed = true;
return this;
}
/// RU: Инициализация экземляпяра [value].
/// ENG: Initialization instance [value].
///
/// return [Binding]
Binding<T> toInstance(T value) {
_mode = Mode.INSTANCE;
_instance = value;
_isSingeltone = true;
return this;
}
/// RU: Инициализация экземляпяра  через провайдер [value].
/// ENG: Initialization instance via provider [value].
///
/// return [Binding]
Binding<T> toProvide(T Function() value) {
_mode = Mode.PROVIDER_INSTANCE;
_provider = value;
return this;
}
/// RU: Инициализация экземляпяра  как сингелтон [value].
/// ENG: Initialization instance as a singelton [value].
///
/// return [Binding]
Binding<T> singeltone() {
_isSingeltone = true;
return this;
}
/// RU: Поиск экземпляра.
/// ENG: Resolve instance.
///
/// return [T]
T? get instance => _instance;
/// RU: Поиск экземпляра.
/// ENG: Resolve instance.
///
/// return [T]
T? get provider {
if (_isSingeltone) {
_instance ??= _provider?.call();
return _instance;
}
return _provider?.call();
}
}

17
lib/src/factory.dart Normal file
View File

@@ -0,0 +1,17 @@
///
/// Copyright 2021 Sergey Penkovsky <sergey.penkovsky@gmail.com>
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
/// http://www.apache.org/licenses/LICENSE-2.0
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import 'package:cherrypick/src/scope.dart';
abstract class Factory<T> {
T createInstance(Scope scope);
}

36
lib/src/helper.dart Normal file
View File

@@ -0,0 +1,36 @@
///
/// Copyright 2021 Sergey Penkovsky <sergey.penkovsky@gmail.com>
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
/// http://www.apache.org/licenses/LICENSE-2.0
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import 'package:cherrypick/src/scope.dart';
Scope? _rootScope;
class CherryPick {
/// RU: Метод открывает главный [Scope].
/// ENG: The method opens the main [Scope].
///
/// return
static Scope openRootScope() {
_rootScope ??= Scope(null);
return _rootScope!;
}
/// RU: Метод закрывает главный [Scope].
/// ENG: The method close the main [Scope].
///
///
static void closeRootScope() {
if (_rootScope != null) {
_rootScope = null;
}
}
}

53
lib/src/module.dart Normal file
View File

@@ -0,0 +1,53 @@
///
/// Copyright 2021 Sergey Penkovsky <sergey.penkovsky@gmail.com>
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
/// http://www.apache.org/licenses/LICENSE-2.0
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import 'dart:collection';
import 'package:cherrypick/src/binding.dart';
import 'package:cherrypick/src/scope.dart';
/// RU: Класс Module является основой для пользовательских модулей.
/// Этот класс нужен для инициализации [Scope].
///
/// RU: The Module class is the basis for custom modules.
/// This class is needed to initialize [Scope].
///
abstract class Module {
final Set<Binding> _bindingSet = HashSet();
/// RU: Метод добавляет в коллекцию модуля [Binding] экземпляр.
///
/// ENG: The method adds an instance to the collection of the [Binding] module.
///
/// return [Binding<T>]
Binding<T> bind<T>() {
final binding = Binding<T>();
_bindingSet.add(binding);
return binding;
}
/// RU: Метод возвращает коллекцию [Binding] экземпляров.
///
/// ENG: The method returns a collection of [Binding] instances.
///
/// return [Set<Binding>]
Set<Binding> get bindingSet => _bindingSet;
/// RU: Абстрактный метод для инициализации пользовательских экземпляров.
/// В этом методе осуществляется конфигурация зависимостей.
///
/// ENG: Abstract method for initializing custom instances.
/// This method configures dependencies.
///
/// return [void]
void builder(Scope currentScope);
}

126
lib/src/scope.dart Normal file
View File

@@ -0,0 +1,126 @@
///
/// Copyright 2021 Sergey Penkovsky <sergey.penkovsky@gmail.com>
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
/// http://www.apache.org/licenses/LICENSE-2.0
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import 'dart:collection';
import 'package:cherrypick/src/binding.dart';
import 'package:cherrypick/src/module.dart';
Scope openRootScope() => Scope(null);
class Scope {
final Scope? _parentScope;
/// RU: Метод возвращает родительский [Scope].
///
/// ENG: The method returns the parent [Scope].
///
/// return [Scope]
Scope? get parentScope => _parentScope;
final Map<String, Scope> _scopeMap = HashMap();
Scope(this._parentScope);
final Set<Module> _modulesList = HashSet();
/// RU: Метод открывает дочерний (дополнительный) [Scope].
///
/// ENG: The method opens child (additional) [Scope].
///
/// return [Scope]
Scope openSubScope(String name) {
if (!_scopeMap.containsKey(name)) {
_scopeMap[name] = Scope(this);
}
return _scopeMap[name]!;
}
/// RU: Метод закрывает дочерний (дополнительный) [Scope].
///
/// ENG: The method closes child (additional) [Scope].
///
/// return [Scope]
void closeSubScope(String name) {
_scopeMap.remove(name);
}
/// RU: Метод инициализирует пользовательские модули в [Scope].
///
/// ENG: The method initializes custom modules in [Scope].
///
/// return [Scope]
Scope installModules(List<Module> modules) {
_modulesList.addAll(modules);
modules.forEach((module) => module.builder(this));
return this;
}
/// RU: Метод удаляет пользовательские модули из [Scope].
///
/// ENG: This method removes custom modules from [Scope].
///
/// return [Scope]
Scope dropModules() {
_modulesList.removeAll(_modulesList);
return this;
}
/// RU: Возвращает найденную зависимость, определенную параметром типа [T].
/// Выдает [StateError], если зависимость не может быть разрешена.
/// Если вы хотите получить [null], если зависимость не может быть найдена,
/// то используйте вместо этого [tryResolve]
/// return - возвращает объект типа [T] или [StateError]
///
/// ENG: Returns the found dependency specified by the type parameter [T].
/// Throws [StateError] if the dependency cannot be resolved.
/// If you want to get [null] if the dependency cannot be found then use [tryResolve] instead
/// return - returns an object of type [T] or [StateError]
///
T resolve<T>({String? named}) {
var resolved = tryResolve<T>(named: named);
if (resolved != null) {
return resolved;
} else {
throw StateError(
'Can\'t resolve dependency `$T`. Maybe you forget register it?');
}
}
/// RU: Возвращает найденную зависимость типа [T] или null, если она не может быть найдена.
/// ENG: Returns found dependency of type [T] or null if it cannot be found.
///
T? tryResolve<T>({String? named}) {
// 1 Поиск зависимости по всем модулям текущего скоупа
if (_modulesList.isNotEmpty) {
for (var module in _modulesList) {
for (var binding in module.bindingSet) {
if (binding.key == T &&
((!binding.isNamed && named == null) ||
(binding.isNamed && named == binding.name))) {
switch (binding.mode) {
case Mode.INSTANCE:
return binding.instance;
case Mode.PROVIDER_INSTANCE:
return binding.provider;
default:
return null;
}
}
}
}
}
// 2 Поиск зависимостей в родительском скоупе
return _parentScope != null ? _parentScope!.tryResolve(named: named) : null;
}
}