ServiceScope class
Шаблон указателя службы, используемый SharePoint Framework.
Комментарии
ServiceScope предоставляет формализованный способ для компонентов для регистрации и использования зависимостей ("службы"), а также для регистрации различных реализаций в разных областях. Это повышает модульность за счет разделения компонентов из их зависимостей расширяемым способом.
Например, предположим, что различным компонентам требуется доступ к экземпляру IPageManager. Мы могли бы просто сделать PageManager одноэлементным (т. е. глобальной переменной), но это не будет работать, например, если нам нужно создать всплывающее диалоговое окно, требующее второго экземпляра PageManager. Лучшим решением было бы добавить PageManager в качестве параметра конструктора для каждого компонента, которому он нужен, однако в этом случае мы сразу же столкнемся с проблемой, что любой код, вызывающий эти конструкторы, также нуждается в параметре PageManager. В приложении с множеством таких зависимостей бизнес-логика, связывающая многие подсистемы, в конечном итоге выберет параметр конструктора для каждой возможной зависимости, что неловко. Естественным решением было бы переместить все зависимости в класс с именем, например ApplicationContext, а затем передать его в качестве параметра конструктора. Это позволяет передавать PageManager классам, которым он нужен, не загромождая промежуточные классы, которые этого не сделали. Тем не менее, по-прежнему возникает проблема проектирования, из-за того что ApplicationContext имеет жестко заданные зависимости от многих несвязанных вещей. Более гибкий подход заключается в том, чтобы сделать его словарем, который может искать элементы для потребителей или поставщиков, которые знают правильный ключ подстановки (например, ServiceKey). Это популярный шаблон проектирования "указатель служб", знакомый по API SPContext в классической версии SharePoint.
ServiceScope делает эту идею еще дальше в двух важных направлениях: во-первых, она предоставляет механизм определения области, чтобы, например, если у нас есть две разные страницы, каждая из них могла предоставить уникальный экземпляр PageManager, но при этом по-прежнему совместно использовать другие общие зависимости. Во-вторых, это позволяет ServiceKey предоставить реализацию зависимости по умолчанию. Это важно для стабильности API в модульной клиентской среде. Например, предположим, что в версии 2.0 нашего приложения появился новый интерфейс IDiagnosticTracing, который ожидается использовать компонентом версии 2.0. Если компонент версии 2.0 загружается более старым приложением 1.0, он завершится ошибкой. Мы могли бы исправить это, обязав каждого потребителя проверка для любых отсутствующих зависимостей и обработать этот случай, но для этого потребуется много проверок. Лучшее решение заключается в том, чтобы всегда существовала реализация по умолчанию, возможно, просто тривиальное поведение, чтобы компоненты могли предположить, что использование() всегда будет возвращать какой-то объект, реализующий контракт.
Использование: экземпляры ServiceScope создаются путем вызова ServiceScope.startNewRoot() или ServiceScope.startNewChild(). Изначально они находятся в "незавершенном" состоянии, во время которого для регистрации ключей службы может быть вызван метод provide(), но использование() запрещено. После вызова ServiceScope.finish() разрешено использование(), а параметр provide() теперь запрещен. Эта семантика гарантирует, что ServiceScope.consume() всегда возвращает один и тот же результат для одного ключа и не зависит от порядка инициализации. Это также позволяет поддерживать циклические зависимости, не беспокоясь о бесконечных циклах. (Циклические зависимости лучше избегать, однако это трудно гарантировать при работе с компонентами, которые были представлены различными третьими сторонами без какой-либо координации.) Чтобы избежать ошибок, лучше всегда вызывать команду consume() внутри обратного вызова из serviceScope.whenFinished().
Конструкторы
(constructor)(parent) | Создает новый экземпляр |
Методы
consume(service |
Использует службу из область службы. |
create |
Это сокращенная функция, которая эквивалентна созданию нового экземпляра simpleServiceClass, а затем его регистрации путем вызова ServiceScope.provide(). |
create |
Это сокращенная функция, которая создает реализацию по умолчанию для указанного объекта serviceKey, а затем регистрирует ее, вызывая метод ServiceScope.provide(). |
finish() | Завершает последовательность инициализации для область службы. |
get |
Возвращает родительскую область ServiceScope или неопределенное значение, если это корневая область. |
provide(service |
Добавление новой службы в область службы. |
start |
Создает дочернюю область ServiceScope. |
start |
Создание новой корневой области ServiceScope. Только корневые области могут автоматически создавать реализации по умолчанию для объектов ServiceKey. |
when |
Отложите операцию до завершения ServiceScope.finish(). |
Сведения о конструкторе
(constructor)(parent)
Создает новый экземпляр ServiceScope
класса
protected constructor(parent: ServiceScope | undefined);
Параметры
- parent
-
ServiceScope | undefined
Сведения о методе
consume(serviceKey)
Использует службу из область службы.
consume<T>(serviceKey: ServiceKey<T>): T;
Параметры
- serviceKey
-
ServiceKey<T>
Ключ, который использовался при вызове метода provide() для регистрации службы.
Возвращаемое значение
T
Экземпляр службы
Комментарии
Компоненты должны вызывать эту функцию для "использования" зависимости, т. е. поиска serviceKey и возврата зарегистрированного экземпляра службы. Если экземпляр не найден, то экземпляр по умолчанию будет автоматически создан и зарегистрирован в корневом ServiceScope.
createAndProvide(serviceKey, simpleServiceClass)
Это сокращенная функция, которая эквивалентна созданию нового экземпляра simpleServiceClass, а затем его регистрации путем вызова ServiceScope.provide().
createAndProvide<T>(serviceKey: ServiceKey<T>, simpleServiceClass: {
new (serviceScope: ServiceScope): T;
}): T;
Параметры
- serviceKey
-
ServiceKey<T>
Ключ, который можно применять позже для использования службы
- simpleServiceClass
-
{ new (serviceScope: ServiceScope): T; }
Создаваемый класс TypeScript
Возвращаемое значение
T
новый экземпляр класса simpleServiceClass
createDefaultAndProvide(serviceKey)
Это сокращенная функция, которая создает реализацию по умолчанию для указанного объекта serviceKey, а затем регистрирует ее, вызывая метод ServiceScope.provide().
createDefaultAndProvide<T>(serviceKey: ServiceKey<T>): T;
Параметры
- serviceKey
-
ServiceKey<T>
Ключ, который можно применять позже для использования службы
Возвращаемое значение
T
Экземпляр службы, созданный с помощью ServiceKey.defaultCreator
finish()
Завершает последовательность инициализации для область службы.
finish(): void;
Возвращаемое значение
void
Комментарии
При первом запуске ServiceScope он находится в "незавершенном" состоянии, где параметр provide() разрешен, но использование() запрещено. После вызова finish() будет разрешено использовать(), но разрешение provide() запрещено.
Этот формализм предотвращает ряд сложных ситуаций, которые могут привести к ошибкам. Например, предполагается, что Scope2 является дочерним элементом Scope1, а Scope1 предоставляет экземпляр A1 интерфейса A. Если кто-то использует A1 из Scope2 (по наследованию) до вызова Scope2.provide() с помощью A2, последующий вызов Scope2.consume() может вернуть результат, отличный от предыдущего вызова. Такой недетерминированность может привести к непредсказуемым результатам, которые трудно диагностировать.
getParent()
Возвращает родительскую область ServiceScope или неопределенное значение, если это корневая область.
getParent(): ServiceScope | undefined;
Возвращаемое значение
ServiceScope | undefined
Родительская область службы
provide(serviceKey, service)
Добавление новой службы в область службы.
provide<T>(serviceKey: ServiceKey<T>, service: T): T;
Параметры
- serviceKey
-
ServiceKey<T>
Ключ, который в дальнейшем будет применяться для использования службы.
- service
-
T
Регистрируемый экземпляр службы
Возвращаемое значение
T
тот же объект, который передавался в качестве параметра service
Комментарии
ServiceScope.provide() используется для регистрации реализации заданного serviceKey для текущего область и реализации заданного rootServiceKey для корневого область. Его можно использовать только в том случае, если ServiceScope находится в состоянии "незавершенного", т. е. до вызова finish().
startNewChild()
Создает дочернюю область ServiceScope.
startNewChild(): ServiceScope;
Возвращаемое значение
Новый корневой объект ServiceScope.
Комментарии
Области службы образуют древовидную структуру, в результате чего при использовании службы, если ключ явно не предоставлен дочерним область, будет обращаться к родительской иерархии.
startNewRoot()
Создание новой корневой области ServiceScope. Только корневые области могут автоматически создавать реализации по умолчанию для объектов ServiceKey.
static startNewRoot(): ServiceScope;
Возвращаемое значение
Новый корневой объект ServiceScope.
whenFinished(callback)
Отложите операцию до завершения ServiceScope.finish().
whenFinished(callback: () => void): void;
Параметры
- callback
-
() => void
Блок кода, который должен вызывать метод ServiceScope.consume()
Возвращаемое значение
void
Комментарии
Вызов ServiceScope.consume() до вызова finish() является ошибкой. Самый надежный способ защиты компонента от этой ошибки — выполнение вызовов consume() внутри обратного вызова whenFinished(). Если служба область уже завершена, обратный вызов будет выполнен немедленно; в противном случае он будет выполнен позже по завершении область.
ПРИМЕЧАНИЕ. Это не асинхронный обратный вызов. Инициализация ServiceScope обычно является недорогой и кратковременной. Однако поток управления часто проходит через многочисленные конструкторы и базовые классы, которые можно упростить с помощью whenFinished().