Советы по программированию Web-сервисов: Изучение шаблонов проектирования Web-сервисов, Часть 2

Инкапсуляция бизнес-логики при помощи шаблона команда-фасад

Во второй части данной серии документов мы продолжаем обсуждать применение четко сформулированных и проверенных стратегий разработки Web-приложения к области Web-сервисов с обзором шаблона комманда-фасад.

James Snell, Инженер-программист, EMC

Author photoJames Snell является членом команды разработчиков IBM Emerging Technologies Toolkit. Последние несколько лет он занимался исследованиями технологий и стандартов Web-сервисов. На данный момент занимается поддержкой раздела weblog на сайте developerWorks.


developerWorks Contributing author
        level

26.10.2004

В предыдущей части данной серии документов обсуждалось применение стратегии программирования Java Messaging Service для реализации асинхронной програмной модели для Web-сервиса. В настоящем документе мы сфокусируемся на использовании простых устоявшихся моделей проектирования в среде Web-сервисов. Задачей данного руководства является предоставление практических примеров, предлагающих альтернативные способы кодирования реализаций сервиса при выполнении определенных задач.

Шаблон команда-фасад

Разработчики Web-приложений хорошо знакомы с двумя шаблонами - facade и command. Шаблон command facade является комбинацией данных шаблонов, разработанной специально для окружения, ориентированного на сервисы. По существу, он объединяет в себе фундаментальные аспекты обоих исходных шаблонов, что делает его значимым для разработчиков, реализующих интерфейсы Web-сервисов, описанных при помощи WSDL и ставших доступными посредством SOAP-сообщений.

Шаблон команда отличается инкапсулированием отдельных действий в объекты повторного использования, чье поведение может быть параметризировано для каждого запроса.

Рисунок 1. Шаблон команда
Шаблон команда

Объектами команд могут быть объекты, обладающие (stateful) или не обладающие (stateless) состоянием. Команда, имеющая состояние, поддерживает внутреннее состояние собственных данных и переменных, определенных в каждом отдельном случае использования. Экземпляры команд, имеющих состояние, обычно используются однократно или же накапливается и утилизируется по мере того, как они перестают быть нужными клиенту. Присваивание параметров командам, имеющим состоянием, происходит, как при создании экземпляра объекта, так и непосредственно перед вызовом команды путем установки атрибутов. Экземпляры команд, не имеющих состояние, не поддерживают никакого внутреннего состояния, и множество клиентов могут использовать их одновременно без необходимости накапливания и утилизации. Назначение параметров командам, не имеющим состояние, происходит через ввод параметров метода вызова команды.

Шаблон фасад использует отдельный высокоуровневый компонент приложения, служащий для инкапсуляции взаимодействий с компонентами младшего уровня с целью упрощения взаимодействий с системой. Другими словами, фасад может упростить более сложный интерфейс между клиентом и поставщиком сервиса или даже множественные подчиняемые компоненты.

Рисунок 2. Шаблон фасад
Шаблон фасад

Как и команды, фасады также могут иметь или не иметь некое состояние. Фасад, имеющий состояние, поддерживает его в промежутке между вызовами клиентами операций, определенных в фасаде. Фасад, не имеющий состояние, не содержит в памяти предыдущих операций, тем самым он зависит от необходимости передачи ему состояния с каждым вызовом метода.

Шаблон команда-фасад объединяет в себе оба подхода путем представления интерфейса фасада, располагающегося перед одним или несколькими объектами команд. Задачей такого шаблона является получение инкапсуляции бизнес-логики, подобно той, что получается при использовании шаблона команды, однако при этом данный шаблон предоставляет потенциальным клиентам более простой и более дружественный интерфейс.

Рисунок 3. Шаблон команда-фасад
Шаблон команда-фасад

В Web-сервисах компонент фасада в шаблоне команда-фасад соотносится с описанным в WSDL portType, с взаимно однозначным отношением между методами, определенными в фасаде и операциями, определенными для типа порта. Каждый метод может вызывать по очереди один или несколько инкапсулированных объектов команды с целью выполнения определенной операции. Согласно типичному Web-сервису Java, в котором отдельный Java-класс подкрепляет отдельный WSDL portType, основной задачей данного шаблона является перемещение бизнес-логики из класса реализации сервиса в отдельные объекты бизнеса, которыми можно легко управлять, и которые могут быть со временем развернуты.


Реализация примеров команд

Шаблон команда-фасад состоит из двух отдельных типов объектов - Command и Facade. Разработка Facade напрямую связана с разработкой Command, которому он будет передавать полномочия. Сюда входят различные опции параметризации, которые раскрывает каждый тип Command. Следовательно, ключом к правильному проектированию реализации команда-фасад является, прежде всего, проектирование команд, а затем определение подходящего интерфейса фасада.

Данный пример приложения определяет две крайне полезных операции, преобразующие строки с входящей информацией в верхний или нижний регистры. Каждая из этих сложных и требующих большого объема вычислений операций инкапсулирована в двух объектах команды, не имеющей состояния.

Перед началом вам необходимо определить основной интерфейс Command.

Листинг 1. Command.java
package com.ibm.developerworks.wspattern.two;

public interface Command {
  public CommandModel execute(CommandModel model);
}

Интерфейс Command определяет только один метод, называемый execute, принимающий отдельный параметр CommandModel. В сущности, этот параметр является заполнителем интерфейса, который определенные реализации команды реализуют с целью позволения пользователям объектов команд отдавать на вход параметры, определенные данной реализацией команды.

Листинг 2. CommandModel.java
package com.ibm.developerworks.wspattern.two;

public abstract class CommandModel {}

Каждая из бизнес-операций принимает на входе отдельную текстовую строку, поэтому обе из них используют одну и ту же реализацию CommandModel, показанную в Листинге 3.

Листинг 3. CaseCommandModel.java
package com.ibm.developerworks.wspattern.two.commands;

import com.ibm.developerworks.wspattern.two.CommandModel;

public class CaseCommandModel 
  extends CommandModel {

  private String string;

  public String getString() {
    return string;  
  }
  
  public void setString(String string) {
    this.string = string;
  }
}
Листинг 4. UppercaseCommand.java
package com.ibm.developerworks.wspattern.two.commands;

import com.ibm.developerworks.wspattern.two.Command;
import com.ibm.developerworks.wspattern.two.CommandModel;

public class UppercaseCommand 
  implements Command {

  public CommandModel execute(CommandModel model) {  
    if (!(model instanceof CaseCommandModel)) {
      throw new IllegalArgumentException("Invalid command model");
    } else {
      CaseCommandModel umodel = (CaseCommandModel)model;
      if (umodel.getString() == null) {
        throw new IllegalArgumentException("Invalid command model");
      } else {
        umodel.setString(umodel.getString().toUpperCase());
      }
      return umodel; 
    }
  }
}
Листинг 5. LowercaseCommand.java
package com.ibm.developerworks.wspattern.two.commands;

import com.ibm.developerworks.wspattern.two.Command;
import com.ibm.developerworks.wspattern.two.CommandModel;

public class LowercaseCommand 
  implements Command {

  public CommandModel execute(CommandModel model) {  
    if (!(model instanceof CaseCommandModel)) {
      throw new IllegalArgumentException("Invalid command model");
    } else {
      CaseCommandModel umodel = (CaseCommandModel)model;
      if (umodel.getString() == null) {
        throw new IllegalArgumentException("Invalid command model");
      } else {
        umodel.setString(umodel.getString().toLowerCase());
      }
      return umodel; 
    }
  }
}

Обратите внимание, что у обоих объектов LowercaseCommand и UppercaseCommand нет внутреннего состояния. Все, что необходимо каждой команде для выполнения, это быть переданной как часть параметра CommandModel. Обратите также внимание на то, что выполняемый метод возвращает CommandModel. Команда может возвратить любую необходимую реализацию CommandModel. В данном примере тот же объект CommandModel, который передается в команду, обновляется и возвращается обратно к запрашивающему приложению. Такое поведение, однако, не является необходимым.


Реализация фасада

Задачей фасада является упрощение и централизация доступа к базовым объектам команды с целью сделать эти команды более доступными в качестве описанного в WSDL Web-сервиса. Для достижения этой цели методы определяются в интерфейсе Façade. Это позволяет использовать для передачи в качестве параметров методам фасада различные опции параметризации, раскрытые базовыми командами. Один метод интерфейса Facade может выполнить один или несколько объектов команды, так что входные параметры для фасада и значение, возвращаемое методом необходимо тщательно выбирать.

В данном примере интерфейс фасада раскрывает один public метод для каждой команды, как показано в Листинге 6.

Листинг 6. CommandFacadeService_SEI.java
package com.ibm.developerworks.wspattern.two;

public interface CommandFacadeService_SEI extends java.rmi.Remote {
   public java.lang.String toUpper(java.lang.String string);
   public java.lang.String toLower(java.lang.String string);
}

Реализация данного интерфейса подразумевает делегирование каждой операции toUpper и toLower соответствующим объектам команды.

Листинг 7. CommandFacadeService.java
package com.ibm.developerworks.wspattern.two;

import com.ibm.developerworks.wspattern.two.commands.LowercaseCommand;
import com.ibm.developerworks.wspattern.two.commands.UppercaseCommand;
import com.ibm.developerworks.wspattern.two.commands.CaseCommandModel;

public class CommandFacadeService {

  private static final String CMD_TOUPPER = "toUpper";
  private static final String CMD_TOLOWER = "toLower";

  private static java.util.HashMap commands = 
    new java.util.HashMap();
  static {
    commands.put(CMD_TOUPPER, new UppercaseCommand());
    commands.put(CMD_TOLOWER, new LowercaseCommand()); 
  }

  private static Command getCommand(String name) {
    return (Command)commands.get(name);
  }

  public String toUpper(String string) {
    CaseCommandModel model = new CaseCommandModel();
    model.setString(string);
    model = (CaseCommandModel)getCommand(CMD_TOUPPER).execute(model);
    return model.getString();
  }

  public String toLower(String string) {
    CaseCommandModel model = new CaseCommandModel();
    model.setString(string);
    model = (CaseCommandModel)getCommand(CMD_TOLOWER).execute(model);
    return model.getString();   
  }
}

Обратите внимание не то, что объекты UppercaseCommand и LowercaseCommand не имеют состояния, поэтому лучше создать статический кэш вызываемых экземпляров, чем вызывать новый экземпляр при каждом вызове методов toUpper и toLower.

После реализации интерфейса фасада последним шагом является раскрытие его как Web-сервиса. Подразумевается, что класс будет раскрыт как Web-сервис, совместимый с JSR-109. Для генерирования всех необходимых артефактов размещения настоятельно рекомендуется использовать программу, подобную IBM® WebSphere® Studio Application Developer (Application Developer). В данном документе для упрощения задачи содержатся ссылки на загрузку ZIP-файла, содержащего полный исходник в виде проекта Application Developer. Здесь также прилагается EAR-файл, содержащий скомпилированный исходник примера приложения. Эти ссылки располагаются в конце документа.


Резюме

Ключевым преимуществом шаблона команда-фасад является то, что он позволяет инкапсулировать бизнес-логику, стоящую за реализацией Web-сервиса, в отдельные объекты, которыми проще управлять и которые можно со временем изменять. До тех пор пока входящие и исходящие значения реализаций команд остаются постоянными, изменениям в бизнес-логике не требуется воздействовать на уровень реализации Web-сервиса. Более того, подобная реализация объектов команд позволяет повторно использовать бизнес-логику в других областях вашего Web-приложения.

В приведенном в данной статье примере фокусируется внимание на фасаде, не имеющем состояния, в котором используются команды, не имеющие состояния. Использование механизмов наподобие тех, что предоставляются HTTP-сессиями или определенных в структуре WS-Resource, позволяет легко расширить модель для поддержки использования фасадов, имеющих состояние. Такой подход дает множество интересных возможностей.


Загрузка

ОписаниеИмяРазмер
EAR-файл для WebSpherews-tip-altdesign2ear.ear701 KB
Исходный код программы-примераws-tip-altdesign2code.zip719 KB

Ресурсы

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=SOA и web-сервисы
ArticleID=96351
ArticleTitle=Советы по программированию Web-сервисов: Изучение шаблонов проектирования Web-сервисов, Часть 2
publish-date=10262004