2015-05-30 2 views
5

У меня есть две отдельные сущности:Использование FactoryMethod картины

public enum Rule implements Validatable, StringRepresentable{ 
    //... 
} 

и

public inteface Filter extends Validatable, StringRepresentable{ 
    //... 
} 

Где

public inteface Validatable{ 
    public GenericValidator getValidator(); 
} 

и

public interface StringRepresentable{ 
    public String getStringRepresentation(); 
} 

GenericValidator - это абстрактный класс, имеющий ряд подклассов. Я бы не хотел, чтобы пользователи обращались напрямую. Как мне лучше справляться с этими вещами?

Я не понимаю, когда это лучше создать класс как

public class ValidatorFactory{ 
    public Validator getRuleValidator(Rule r){ ... } 
    public Validator getFilterValidator(Filter f){ ... } 
} 

вместо реализации интерфейса Validatable как я показано ранее.

Не может кто-нибудь объяснить, как я могу принять правильное решение? Какие потенциальные обстоятельства требуют применения FactoryMethod плохого решения, и когда это будет действительно хорошо?

UPD:

public interface Validator{ 
    public ErrorCode validate(); 
} 

public abstract class GenericValidator implements Validator{ 
    //... 
} 

ErrorCode класс инкапсулирует результат проверки (null если valiadtion как будет завершен succsfully).

+0

Если у вас есть такие проблемы, как подклассы 'GenericValidator', использование' ValidatorFactory' должно работать для вас, так как вам просто нужен соответствующий валидатор для вашей службы, верно? Кроме того, когда вы говорите: «Я бы не хотел, чтобы пользователи имели доступ напрямую», как вы это понимаете? – ha9u63ar

+0

@ ha9u63ar На самом деле, да. Мне просто нужен валидатор для службы. И у меня есть dillema: создание фабрики или реализация интерфейса. –

+0

@ ha9u63ar__how вы имеете в виду? Я имею в виду, что конечный пользователь должен знать только о классе GenericFactory и его методе 'validate()', который будет переопределен в подклассах. Вот почему я думаю об инкапсуляции подклассов и их создании. –

ответ

3

Единой Ответственность Принцип

Строительство валидатора является один ответственностью, фильтр или правило, вероятно, носит еще один. Это означает, что мы должны разделить его, и обычно мы делаем это, инкапсулируя логику создания экземпляра в шаблон Factory.

Также обратите внимание, что реализация Validatable означает ValidatorFactory.Мой ответ был бы - объединить оба решения:

public class FilterImpl implements Filter { 
    private final Validator validator; 

    public FilterImpl(Validator validator) { 
     this.validator = validator; 
    } 

    @Override 
    public getValidator() { 
     return this.validator; 
    } 

    //... 
} 

public class FilterFactory { 
    private final ValidatorFactory validatorFactory = new ValidatorFactory(); 

    public Filter createFilter() { 
     return new FilterImpl(valdatorFactory.createFilterValidator()); 
    } 
} 

Это называется Dependency Injection. интерфейс

+0

Представьте себе ситуацию, когда у нас есть метод, например 'public void method (Фильтр f)', и нам нужно получить значение validor параметра внутри его тела. Что делать, если мы передали значение null в качестве параметра? Тогда мы получим NPE. Вы сознательно не уважаете это дело? –

+0

Просто закрепите нулевой указатель, вот и все. if (f == null) {// ваше решение, что делать}. Я действительно не беспокоюсь. Вам иногда нужно передавать параметры, все время вам нужно убедиться, что они не являются нулевыми ... – macias

+0

Насколько я понял ваше решение, мы предоставляем конкретную реализацию Validator через конструктор. Я просто должен сказать, что мы используем Spring IoC, поэтому можем легко выполнять инъекции зависимостей. Должны ли мы действительно использовать его здесь? –

3

Я использую этот шаблон в двух основных случаях:

A) Строительство объекта не тривиальное - Я не доверяю пользователям по API, чтобы сделать это правильно

B) Есть больше реализаций, и я хочу сам выбрать правильный.

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

Всегда стремиться к простоте и простоте использования для пользователя. Задайте себе следующие вопросы:

  1. Является ли API понятным?
  2. Является ли API легким/забавным в использовании?
  3. Является ли это надежным? (Я должен попытаться довольно трудно злоупотреблять им)
+0

Внутренние интерфейсы API не просто понять, поэтому я хочу его инкапсулировать. –

+0

Тогда метод Factory - очень хороший способ инкапсулировать конструкцию экземпляра. –

+0

Но что, если у меня есть 1000 полностью разделенных сущностей, и любой из них должен быть проверен. Тогда мой завод будет содержать 1000 заводских методов? Разве это не плохой дизайн? –

3

валидатор может выглядеть следующим образом:

public interface Validator { 
    public int validate(); 
} 

интерфейс фильтра может выглядеть следующим образом:

public interface Filter { 
    public String getParameters(); // some related methods.. 
    public int currentLength(); 
    .... 
} 

Правило интерфейса:

public interface Rule { 
    public String getRule(); 
} 

FilterValidator может выглядеть следующим образом:

public class FilterValidator implements Validator{ 

private Filter f; 

public FilterValidator(Filter f){ 
    this.f = f; 
} 

@Override 
public int validate() { 
    // validate f and return errorcode 
    String params = f.getParameters(); 
    int strLength = f.currentLength(); 
    ..... 

    return 0; 
} 

} 

Создание фабрики лучше скрыть внутреннюю логику валидаторов.

public class ValidatorFactory { 

public Validator getRuleValidator(Rule r){ 
    return null; 
} 

public Validator getFilterValidator(Filter f){ 
    FilterValidator fv = new FilterValidator(f); 
    return fv; 
} 
} 

Теперь клиент будет вызывать этот factoy так:

public class ClientDemo { 

    private class MyFilter implements Filter{ 

    private String filterInput; 
    public MyFilter(String input){ 
     this.filterInput = input; 
    } 

    @Override 
    public String getParameters() { 
     return null; 
    } 

    @Override 
    public int currentLength() { 
     return this.filterInput.length(); 
    } 

} 

    public void testValidators(){ 

     ValidatorFactory factory = new ValidatorFactory(); 
     Validator v = factory.getFilterValidator(new MyFilter("filter string goes here...")); 
     v.validate(); 
    } 
} 
} 

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

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