2014-10-04 4 views
0

Этот вопрос использует примеры Java, но он касается проблемы, применимой к любому ООП. Я хочу показать некоторые веб-сервисы, чтобы другие приложения могли их использовать. Я создал файл jar/library, который обрабатывает все материалы соединения и преобразование строки/xml в pojo. Я создал класс «фасад», который имеет 1 метод для каждого вызываемого веб-сервиса. Например. в псевдокоде:Повторное использование «настроек» по различным вызовам метода

class ServiceInvoker 
{ 
    //constructor 
    ... 

    //methods 
    public List<Product> getProducts() 
    public ProductReference getProductReferences(int productId) 
    ... 
} 

Проблема в том, что для большинства веб-сервисов требуется множество параметров. Например, всякий раз, когда вы имеете дело с продуктами, вы либо получаете полную подробную информацию, либо можете получить только самую основную информацию. То же самое касается только последней/старой информации. Лучше всего получить только несколько продуктов, но иногда вам действительно нужна дополнительная информация, поэтому для определения параметров используются наилучшие способы использования всех вариантов использования. Я нашел 3 возможных способа борьбы с этим.

  1. Добавьте необходимые параметры для каждого вызова метода. Преимущество: просто понять, понятно, когда вы вызываете метод «ваши настройки».
  2. Создайте несколько сеттеры в ServiceInvoker, как это:

общественного недействительными setInfoMode (режим Infomode) { this.infoMode = режим; }

Где InfoMode бы класс как это перечисление: InfoMode.DETAILED, InfoMode.BASIC. Преимущество этой схемы заключается в том, что разработчикам нужно только установить режим «один раз», а затем все будущие служебные вызовы будут использовать этот режим. Это может сэкономить целую кучу аргументов несколькими способами, особенно потому, что некоторые службы могут обмениваться настройками, и, вероятно, одна и та же услуга вызывается несколько раз. Основным недостатком этой схемы является ясность: при вызове службы «getProducts» ответ может сильно различаться в зависимости от ранее установленных режимов. Ранее сказал, преимущество будет потеряно, если разработчики должны были сделать некоторые предварительной обработки, как это:

if (serviceInvoker.getInfoMode != InfoMode.DETAILED) 
{ 
    serviceInvoker.setInfoMode(InfoMode.DETAILED); 
} 

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

Третий вариант состоит в том, чтобы объединить как 1, так и 2. Имейте метод без параметров, который использует ранее установленные режимы, но также предоставляет метод с аргументами, который принимает аргументы, и они временно перезаписывают установленные режимы для вызова метода , Недостатком этой схемы является «удвоение» всех методов. Внезапно мой класс invoker становится огромным, и он начинает пахнуть, как анти-шаблон «огромный божественный класс».

Каковы некоторые рекомендации по этой проблеме? Существует ли шаблон проектирования для этой ситуации?

ответ

1

Этот вопрос, вероятно, будет закрыт, поскольку он в основном основан на мнениях (потому что это так), но он чище просто представляет конкретные типы запросов как DTO. Когда вы вызываете класс «ServiceInvoker», я думаю Command Pattern. Что это означает для вашего дизайна, так это то, что аргументы вашего Фасада должны быть самоочевидными пакетами, которые инкапсулируют всю информацию, необходимую службе для выполнения своих обязанностей. Эта конструкция также должна устранить необходимость использования нескольких методов в вашем классе.

Это означает, что для абонентов вашей службы это означает, что они будут передавать разные типы аргументов (которые имеют общий предок) в одну точку входа в ServiceInvoker, ServiceInvoker#invoke. Затем этот метод будет принимать классы, которые все распространяются на ProductRequest.ServiceInvoker может затем делегировать запрос соответствующему обработчику команд. Иллюстрировать

  1. Создать базовый класс ProductRequest. Этот базовый класс должен содержать информацию, которая будет общей для всех типов операций

    public abstract class ProductRequest{ 
        private InfoMode infoMode; 
        private String requestType; 
        //getters and setters 
    
        //trying to avoid violating Javabean convention here 
        private void setRequestName(){ 
         this.requestType = this.getClassName().toString(); 
        } 
    } 
    
  2. Отдельных типы запросов службы должны распространяться ProductRequest. Настройте по мере необходимости для каждого типа операции.

  3. Создайте специализированные типы ProductRequestHandler, которые будут обрабатывать конкретные запросы на работу. Давайте попробуем один, который специально обрабатывает ссылку продукта просит

    public class ProductReferenceReqHandler implements ProductRequestHandler<ProductReferenceRequest>{ 
    
         @Override 
         public ProductResponse handleRequest(ProductReferenceRequest req){ 
         //implementation grime goes here 
         } 
    
        } 
    
  4. Вы должны иметь стек ProductRequestHandler с в карте, шпонкой по типу запроса. Эта карта должна быть членом вашей ServiceInvoker

  5. С доступом к карте возможных обработчиков запросов, ваш Вызывающий только нужно иметь один метод: invoke

    public class ServiceInvoker{ 
         private Map<String,ProductRequestHandler> handlers; 
         //work out some logic to instantiate and populate the map with the available handlers 
    
         public ProductResponse invoke(ProductRequest req){ 
          ProductRequestHandler handler = handlers.get(req.getRequestType()); 
          ProductResponse resp = handler.handleRequest(req); 
    
         } 
    
        } 
    

Что Вы получаете чистый, гибкий интерфейс, который позволяет избежать ненужного беспорядка в вашем Facade и дает интуитивно понятный контракт (с помощью интуитивно названных DTO) вашим клиентам

+0

Excellent дизайн рисунок! Одно из предложений: вместо того, чтобы полагаться на карту «обработчиков», я заставил каждый класс запроса иметь метод getHandler() (я сделал это, сделав абстрактный метод в классе baseRequest, который наследует каждый другой запрос), который возвращает подходящий обработчик. Этот обработчик на самом деле является статическим окончательным атрибутом класса запроса, поэтому он не приведет к ложному экземпляру объектов обработчика. – user1884155

+0

@ user1884155 - Это немного анти-шаблон. Классы запроса должны быть только данными запроса. В классах запросов не должно быть информации об их контексте выполнения или вызывающем обработчике. Выпекая информацию обработчика в запросе, вы также потеряете гибкость, которую предоставила бы вам карта обработчиков. Наличие карты обработчиков означает, что вы можете добавлять или удалять обработчики по своему усмотрению или даже переименовывать некоторые обработчики для обработки разных типов запросов. – kolossus

+0

Я не сразу вижу, почему у запроса не может быть метода «suggestHandler». СервисInvoker никоим образом не обязан фактически использовать этого обработчика, он может использовать любой обработчик, которого он хочет (если контекст оправдывает его), и запрос не знает, что означает «для вызова». Единственное, что говорит класс запросов: «Эй, если кто-то хочет обработчика, который может мне помочь, почему бы не попробовать этот по умолчанию?». Это основной полиморфизм, который определенно не является анти-шаблоном. Заполнение хэш-карты, закодированной с данными запроса-> обработчика, пахнет как анти-шаблон (ремонтопригодность?) – user1884155

Смежные вопросы