Ява - Поведенческие решения "instanceof" против флага - PullRequest
0 голосов
/ 02 мая 2018

В настоящее время я работаю над фрагментом кода, в котором поведенческие решения принимаются на основе того, принадлежит ли объект запроса к определенному подтипу, например:

class Request{
    public void doThing(){
        System.out.println("doing Thing...");
    }
}

class SpecialRequest extends Request{
    ...
}

void method(Request request){
    if(request instanceof SpecialRequest){
        System.out.println("is special...");
    }
    request.doThing();
}

В данном случае в SpecialRequest больше ничего не реализовано, что отличало бы его от обычного запроса. Теперь у меня вопрос: есть ли у этого стиля какие-либо преимущества или недостатки:

class Request{
    ...

    public boolean isSpecial(){
        return special;
    }

    public void doThing(){
        System.out.println("doing Thing...");
    }
}

void method(Request request){
    if(request.isSpecial()){
        System.out.println("is special...");
    }
    request.doThing();
}

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

Заранее спасибо.

РЕДАКТИРОВАТЬ: Прежде всего, спасибо за быстрый ответ. Я должен был, вероятно, упомянуть, что мой Запрос и мой Специальный запрос должны просто переносить данные и не содержать никакой логики. Вот как все программное обеспечение разработано. Мой метод просто потребляет запрос и должен вести себя по-разному в зависимости от того, является ли запрос особенным или нет. «instanceof» просто кажется мне грязным кодом, но логическое значение также не совсем верно. Любой совет по-прежнему приветствуется.

Ответы [ 3 ]

0 голосов
/ 02 мая 2018

1.- вместо этого - оператор сравнения типов, потому что он сравнивает экземпляр с типом. Возвращает либо true, либо false. Если вы примените оператор instanceof к любой переменной, которая имеет нулевое значение, она возвращает false.

2.- isSpecial (), это ваш собственный метод. Вы можете делать все, что захотите, в этом фрагменте кода, поэтому сравнение в этом случае зависит от вас.

3.- Вы должны знать, что когда вы используете instanceof, при сравнении также выполняется приведение класса к упомянутой переменной, поэтому, если это невозможно, вы должны получить ошибку во время компиляции. смотрите это: ошибка времени компиляции с instanceof

4.- Если вы часто используете этот оператор, вы должны проверить его, потому что это сигнал какого-то плохого кода. Для более подробной информации смотрите: использование instaceof

0 голосов
/ 03 мая 2018

Вы можете также рассмотреть возможность использования шаблона посетителя (https://en.wikipedia.org/wiki/Visitor_pattern),, так как он обеспечивает безопасность типов и не требует проверки экземпляра. Кроме того, более очевидно, когда вам нужно расширять / модифицировать свой код, когда вы создать новый тип запроса (например, «VerySpecialRequest»).

Все, что вам нужно сделать, - это создать интерфейс с методами посещения для каждого типа, для которого вы хотите выполнить специальный код, например:

public interface RequestProcessor {
  void visit(Request request);
  void visit(SpecialRequest specialRequest);
}

Классы запросов нуждаются в методах accept, которые ничего не делают, кроме как сами вызывают посетителя:

public class Request {

  ...

  void accept(RequestProcessor requestProcessor) {
    requestProcessor.visit(this);
  }
}

То же самое для SpecialRequest:

public class SpecialRequest extends Request {

  ...

  @Override
  void accept(RequestProcessor requestProcessor) {
    requestProcessor.visit(this);
  }
}

Тогда вы можете просто реализовать свою логику в классе, который реализует интерфейс (здесь как анонимный класс):

RequestProcessor requestProcessor = new RequestProcessor() {

  @Override
  public void visit(Request request) {
    System.out.println("I'm a normal request");
  }

  @Override
  public void visit(SpecialRequest specialRequest) {
    System.out.println("I'm a special request");
  }
};


Request request = new Request();
request.accept(requestProcessor);

SpecialRequest specialRequest = new SpecialRequest();
specialRequest.accept(requestProcessor);

Как видите, экземпляров проверок больше нет. Еще одним преимуществом этого является то, что вы можете «обрабатывать запросы», даже если они не являются прямым подклассом «Request» - все, что вам нужно сделать, это извлечь метод accept в его собственном интерфейсе. Надеюсь, это поможет.

0 голосов
/ 02 мая 2018

Очевидным преимуществом использования метода является то, что он не тесно связан с конкретным типом. Вы можете добавить новый класс VerySpecialRequest, который также обеспечивает такое поведение, и вам необязательно расширять SpecialRequest, чтобы сделать это.


Однако более насущная проблема заключается в том, что у вас есть явное условное ветвление вообще. Объект должен отвечать за определение того, требуется ли какое-либо дополнительное поведение, и тогда неприятная условная логика исчезнет совсем:

class Request{
    public void doThing(){
        System.out.println("doing Thing...");
    }
}

class SpecialRequest extends Request{
    @Override
    public void doThing(){
        super.doThing();
        System.out.println("is special...");
    }
}
...