2016-10-09 3 views
1

Я работаю над клиентом, который использует стандартизованный веб-сервис, однако один из поставщиков ведет себя несколько иначе, так что мы должны учитывать эти поведения. Для этого мы используем перечисление:Использование базового enum как значения по умолчанию для зависимых перечислений

public enum ServiceProviderType { 
    FOO, BAR; 

    public ServiceProviderType checkService(String url) { 
     if (url.equals("http://www.example.com")) { 
      return ServiceProviderType.FOO; 
     } else { 
      return ServiceProviderType.BAR; 
     } 
    } 
} 

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

public enum LayerServiceProviderType { 
    FOO("#ff0000"), 
    BAR("#ff5555"); 

    private String colour; 

    public ServiceProviderType(String colour) { 
     this.colour = colour; 
    } 

    public String getColour() { 
     return colour; 
    } 

    public ServiceProviderType checkService(String url) { 
     if (url.equals("http://www.example.com")) { 
      return ServiceProviderType.FOO 
     } else { 
      return ServiceProviderType.BAR; 
     } 
    } 
} 

Это прекрасно работает, когда мы хотим обрабатывать несколько слоев и относиться к ним, как и всем являющимся производному тому же базовому перечислимому за исключением. По сути, мы хотим обрабатывать Layer1ServiceProviderType.BAR как эквивалент Layer2ServiceProviderType.BAR. Но мы не можем перечислить перечисления, и даже попытка сделать это, похоже, нарушает все виды принципов звукового дизайна.

Моя первая мысль была иметь интерфейс, который содержит перечисление:

interface ServiceProvider { 
    ServiceProviderType {FOO, BAR}; 

    ServiceProviderType getServiceProviderType(); 

    ServiceProvider checkService(String url); 
} 

public enum LayerServiceProvider implements ServiceProvider { 
    FOO (ServiceProviderType.FOO, "#ff0000"), 
    BAR (ServiceProviderType.BAR, "#ff0000"); 

    public LayerServiceProvider(ServiceProviderType serviceProviderType, String colour) { 
     this.serviceProviderType = serviceProviderType; 
     this.colour = colour; 
    } 

    @Override 
    public ServiceProviderType getServiceProviderType() { 
     return this.serviceProviderType; 
    } 

    @Override 
    public ServiceProvider checkService(String url) { 
     if (url.equals("http://www.example.com")) { 
      return LayerServiceProviderType.FOO 
     } else { 
      return LayerServiceProviderType.BAR; 
     } 
    } 
} 

Но, кажется, взвинченный мне иметь перечисление с в перечислении, что каждый трюм тот же диапазон значений. Есть лучший способ сделать это?

+0

Любая причина, вы не можете просто добавить '' colour' в ServiceProviderType'? – Andreas

+0

'colour' и другие переменные не будут распространены для каждого' ServiceProviderType' - переменные будут меняться в соответствии с тем, что мы запрашиваем у поставщика услуг. Общность - это перечисление. – Michael

+0

Мне действительно непонятно, в чем проблема, что у вас есть. На самом деле это не вопрос об перечислениях почти так же, как о спецификации проблемной области и модели. «Плохо разработанный API может испортить класс навсегда» - Дж. Блох. Возможно, перечисление - это изящный способ пойти (перечисление стратегий - вещь), но, возможно, нет. Я недостаточно знаком с вашим проектом, чтобы знать, как помочь. – scottb

ответ

0

Возможно, Visitor Pattern - это то, что вы ищете.

Используется с перечислением, он в основном позволяет добавлять зависящую от перечислимого числа логику без использования операторов switch.

Пример:

public enum ServiceProviderType { 
    FOO { 
     @Override public <T> T apply(Action<T> action) { return action.doFoo(); } 
    }, 
    BAR { 
     @Override public <T> T apply(Action<T> action) { return action.doBar(); } 
    }; 

    public interface Action<T> { 
     T doFoo(); 
     T doBar(); 
    } 

    public abstract <T> T apply(Action<T> action); 

    public static ServiceProviderType checkService(String url) { 
     if (url.equals("http://www.example.com")) 
      return FOO; 
     return BAR; 
    } 
} 

public class LayerServiceProviderType implements ServiceProviderType.Action<String> { 
    @Override 
    public String doFoo() { 
     return "#ff0000"; 
    } 
    @Override 
    public String doBar() { 
     return "#ff0000"; 
    } 
} 

public class Main { 
    public static void main(String[] args) { 
     ServiceProviderType type = ServiceProviderType.checkService(""); 

     String colour = type.apply(new LayerServiceProviderType()); 
    } 
} 
+0

Мне нравится этот шаблон, но мне интересно, как он работает в случае, когда LayerServiceProviderType должен возвращать несколько переменных. Например, когда мне может потребоваться переменная 'colour' и переменная' name' (и многое другое). – Michael

+0

В этом случае вы можете рассматривать класс 'Layer ...' выше как * заводский класс *, возвращая объект с помощью набора методов getters. Это не ограничивается только методами геттера; это может быть поведенческие методы, что делает его более похожим на [Strategy Pattern] (https://en.wikipedia.org/wiki/Strategy_pattern), в основном используя «фабрику» для получения зависящей от перечислимого числа «стратегии». – Andreas

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