- PVSM.RU - https://www.pvsm.ru -
Salesforce.com [1] — популярная CRM-система.
Service Locator [2] — шаблон проектирования, позволяющий инкапсулировать процесс получения сервиса с высоким уровнем абстракции. Шаблон использует центральный реестр, называемый «Service Locator», который по запросу возвращает информацию необходимую для выполнения задачи.
Часто наши проекты приходят к тому, что становится необходимым начать использовать принцип инверсии зависимостей. Salesforce не имеет готовых DI контейнеров, а также отсутствует Reflection API для реализации собственного. Поэтому мы решили использовать в своих проектах реализацию шаблона Service Locator. Это позволило нам избавиться от следующих проблем:
Если с первым пунктом всё понятно, то для второго я хотел бы привести несколько примеров из жизни:
Наше решение включает в себя класс-локатор, а также фабрики для удобства использования.
Первым делом мы создаем класс MyServiceLocator, который будет отвечать за поиск необходимого сервиса в зависимости от контекста выполнения:
public class MyServiceLocator {
private static final Map<Type, Type> customTypesMap = new Map<Type, Type> {
MyIDatabase.class => MyDatabase.class,
// Services
MyICustomObjectService.class => MyCustomObjectService.class,
MyIHttpService.class => MyHttpService.class,
// DAOs
MyICustomObjectDao.class => MyCustomObjectDao.class
};
private static final Map<Type, Type> testTypesMap = new Map<Type, Type> {
// Mocks
MyICustomObjectDao.class => MyTestCustomObjectDao.class,
MyIHttpService.class = MyTestHttpService.class
};
public static Type resolve(Type t) {
if (Test.isRunningTest()) {
if (testTypesMap.containsKey(t)) {
return testTypesMap.get(t);
}
}
if (customTypesMap.containsKey(t)) {
return customTypesMap.get(t);
}
return t;
}
}
В данном решении можно использовать Custom Settings для хранения соответствия типов, при этом можно использовать функцию Type.forName(String typeName) [4].
Обычно данный шаблон мы комбинируем с Factory. Для этого создаются подобные следующему классы, объединяющие сервисы различных слоёв приложения (DaoFactory, ServiceFactory и так далее):
public class MyServiceFactory {
private static Object initService(Type t) {
Type typeForService = MyServiceLocator.resolve(t);
return typeForService.newInstance();
}
public static MyIHttpService getHttpService() {
return (MyIHttpService)initService(MyIHttpService.class);
}
public static MyICustomObjectService getCustomObjectService() {
return (MyICustomObjectService)initService(MyICustomObjectService.class);
}
}
Использование сводится к вызову одной строчки для инициализации и дальнеешее использование сервисов в остальных методах.
public class MyController {
private MyIHttpService httpService;
private MyICustomObjectService customObjectService;
public MyController() {
initServices();
}
private void initServices() {
httpService = MyServiceFactory.getHttpService();
customObjectService = MyServiceFactory.getCustomObjectService();
}
...
}
Надеюсь это простое и удобное решение поможет кому-то из русскоязычного salesforce-коммьюнити.
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/pesochnitsa/88218
Ссылки в тексте:
[1] Salesforce.com: https://www.salesforce.com/
[2] Service Locator: http://en.wikipedia.org/wiki/Service_locator_pattern
[3] Test.setMock(...): https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_methods_system_test.htm#apex_System_Test_setMock
[4] Type.forName(String typeName): https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_methods_system_type.htm#apex_System_Type_forName
Нажмите здесь для печати.