Метод, возвращающий альтернативные структуры данных на основе результата выполнения - PullRequest
3 голосов
/ 26 апреля 2019

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

public Result checkFile(File file) {
    ...
}

Есть два способа сделать это ...

Иметь класс Result так:

class Result {

    private Type type;
    private String message;

    enum Type { 
        RECOGNIZED, UNRECOGNIZED
    }

}

Или сделай так:

class Result {
}

class Unrecognized extends Result {
}

class Recognized extends Result {
    private String message;
}

Я склонен использовать второй метод, хотя мне придется проверять результат, используя instanceof, и я прочитал, что instanceof следует по возможности избегать, но при этом избегается пустое сообщение когда результат не распознан. В этом примере пустое сообщение не будет большой проблемой, но что, если с распознанным результатом связано намного больше данных? Мне кажется худшей практикой создавать экземпляр класса, который может иметь все нулевые поля.

Как лучше всего справляться с этой ситуацией? Есть ли какой-то стандартный метод или шаблон?

Ответы [ 5 ]

2 голосов
/ 26 апреля 2019

Два класса могут быть излишними, потому что это один и тот же класс объекта.Также enum с двумя значениями, которые просто собирают true и false, не требуется.Одного class Result должно хватить, и это также уберет спрос на общий interface.Я бы сказал, что "нет сложности сверх необходимого" ...

class RecognitionResult {

    private String message = "default message";
    private boolean recognized = false;

    public Result() {}

    public Result(boolean value) {
        this.setRecognised(value);
    }

    public boolean setRecognised(boolean value) {
        this.recognized = value;
    }

    public boolean setMessage(@NonNull String value) {
        this.message = value;
    }

    public boolean getRecognised() {
        return this.recognized;
    }

    @Nullable
    public String getMessage() {
        return this.recognized ? this.message : null;
    }
}

, тогда можно просто сделать:

return new RecognitionResult(true);

и interface для асинхронных обратных вызовов может выглядеть примерно так:

interface Recognition {
    void OnComplete(RecognitionResult result);
}

или, если вы действительно хотите оптимизировать:

interface Recognition {
    void OnSuccess(RecognitionResult result);
    void OnFailure(RecognitionException e);
}
1 голос
/ 26 апреля 2019

Конечно, здесь нет «правильного» дизайна - все зависит от того, каким путем вы идете. Однако я считаю, что современная тенденция в OOD - минимизировать использование расширений и использовать делегирование и реализацию интерфейсов везде, где это возможно.

Как правило, всякий раз, когда вы думаете об использовании instanceof, пересматривайте свой дизайн.

Это было бы мое предложение:

interface Result {
    boolean isRecognised();
    String getMessage();
}

class RecognisedResult implements Result {
    private final String message;

    public boolean isRecognised() {
        return true;
    }

    public String getMessage() {
        return message;
    }
}

class UnrecognisedResult implements Result {
    public boolean isRecognised() {
        return false;
    }

    public String getMessage() {
        throw new UnsupportedOperationException("No message for unrecognised results");
    }
}
0 голосов
/ 04 июня 2019

Функциональный способ сделать это - использовать тип Either, который не поставляется с JDK, но доступен в библиотеке vavr . Судя по вашим комментариям в этой теме, вы не совсем понимаете, как работает наследование типов. В этом случае функциональное решение может быть излишним, и я бы предложил использовать решение @ sprinter's .

.
0 голосов
/ 04 июня 2019

Вы можете использовать Java Необязательный тип и возвращать Optional.empty(), если контент не распознан, и Optional.of(new Result(...)), если контент распознан.Тогда вам не нужно перечисление в вашем типе Result.

public Optional<Result> checkFile(File file) {
    if( /* is recognized */ ) { 
        return Optional.of(new Result(...));
    }
    else {
        return Optional.empty();
    }
}
0 голосов
/ 26 апреля 2019

вы можете посмотреть, как Retrofit реализует вашу концепцию «распознан» и «сообщение» https://square.github.io/retrofit/2.x/retrofit/retrofit2/Response.html. это похоже на ваш первый метод.

то, что они сделали, - это создали класс с именемОтвет, содержащий метод isSuccessful () и метод body (), содержащий полезную нагрузку, если она успешна (или ноль, если она неудачна.

, вы можете попробовать что-то вроде следующего

class Result {

    private Type type;
    private String message;

    public bool isSuccessful(){
            return type == RECOGNIZED;
    }

    public String getMessage(){
            return message; //null if unrecognized.
    }

    enum Type { 
        RECOGNIZED, UNRECOGNIZED
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...