Россия, г. Москва |
Взаимодействие компонент распределенной системы
Использование свойств удаленных объектов
Рассмотрим следующий фрагмент кода, заполняющий свойства удаленного объекта информацией о человеке и вызывающий некий удаленный метод для ее обработки.
processing.FirstName = "Иван"; processing.SecondName = "Иванов"; processing.ThirdName = "Иванович"; processing.City = "Москва"; result = processing.Run();
Если processing – локальный объект, то в методе Run() он будет иметь доступ к установленным здесь значениям своих методов. Предположим, что processing – удаленный объект. В этом случае возможны, например, следующие варианты.
- Используется модель единственного вызова, причем установка свойства объекта рассматривается как вызов метода установки свойства ( set в C#). В этом случае к моменту вызова метода Run состояние полей объекта не задано (при отсутствии пула объектов) или неопределенно (при использовании пула объектов).
- Используется модель единственного вызова, но установка свойств объекта не рассматривается как удаленный вызов. Например, их значения сохраняются на стороне клиента и передаются на сервер в момент вызова метода, где на основе этих значений заполняются поля объекта. В этом случае результат будет корректен.
- Используется модель активации по запросу клиента, или такой вариант модели единственного вызова, в котором присваивание свойств объекта приводит к передаче данных на сервер без последующей деактивации объекта (по существу такая модель уже не является моделью одного вызова). В этом случае результат так же будет корректен, но присваивание свойств объекту приводит к непроизводительным удаленным вызовам.
- Используется модель одного экземпляра. В этом случае результат будет некорректным, поскольку поля объекта будут заполняться параллельно разными клиентами.
Таким образом, один и тот же код может давать разные результаты в зависимости от модели использования удаленной компоненты, причем только в одном из примеров был получен корректный результат при минимальных накладных расходах. Можно сделать заключение, что использование в программе свойств удаленного объекта приводит к зависимости ее результата от используемой промежуточной среды и ее конфигурации. Наилучшим вариантом решения этой проблемы представляется отсутствие публичных свойств у удаленного объекта. В таком случае использование удаленного объекта может не отличаться от вызова метода локального объекта. Однако применение такого подхода "в лоб" (так называемый chunky design ) может привести к плохо читаемому коду, например следующему.
result = processing.Run("Иванов", "Иван", "Иванович", "Москва");
В отличие от предыдущего фрагмента, это код не является самодокументирующимся, и увеличивает вероятность ошибки в последовательности аргументов вызываемого метода. В данном примере так же наблюдается смешивание двух сущностей: объекта, содержащего данные о человеке, и объекта, производящего с ним операции. Правильный подход заключается в создании маршализируемого по значению класса, содержащего все параметры удаленного вызова, и передача его экземпляра как параметра удаленного вызова метода.
person.FirstName = "Иван"; person.SecondName = "Иванов"; person.ThirdName = "Иванович"; person.City = "Москва"; result = processing.Run(person);
Для многих задач представляет интерес вопрос модификации поведения удаленного объекта путем добавления некоторого дополнительного кода. Рассмотрим следующий фрагмент кода, вызывающий некий математический метод для заданной функции и заданного отрезка значений аргумента. Было бы удобно отделить реализацию самого математического метода от применяемой функции.
task.Epsilon = 1e-5: task.X1 = -1; task.X2 = 1; task.MaximumSteps = 20; task.Function += X2Function; result = processing.Run(processingArguments); ... double X2Function(double x) { return x*x; }
Если processing – это удаленный объект, то данный код, вероятно, приведет к многочисленным удаленным вызовам функции X2Function. В этом случае приведенный код имеет два главных недостатка – во первых, клиент для этого должен так же поддерживать удаленные вызовы, во вторых, он неэффективен, если удаленный метод постоянно вызывает находящуюся на стороне клиента функцию.
Для решения возникшей проблемы в общем случае требуется передать тем или иным способом код функции (и, возможно, используемых ею данных) на сервер с реализующим математический метод удаленным объектом. Такой подход неприменим в общем случае по соображениям безопасности, но при необходимости можно, например, при использовании .NET Framework передать клиенту сборку с требуемым кодом как данные при удаленном вызове. В качестве возможной альтернативы для математических задач может выступать и передача кода функции для дальнейшей компиляции встроенным компилятором языка C#.