Пусто оцените как возвращаемый параметр

Одна техника для использования должна разработать код модульного теста с C++ xUnit платформа (и компилятор C++) при поддержании источника для целевой системы как C модули.

Удостоверяются, что Вы регулярно компилируете свой источник C в соответствии с Вашим кросс-компилятором, автоматически с Вашими модульными тестами, если это возможно.

11
задан Michael Myers 10 August 2009 в 19:23
поделиться

8 ответов

Вот лучшая из множества миров реализация.

// Generic interface for when a client doesn't care
// about the return value of a command.
public interface Command {
    // The interfaces themselves take a String[] rather
    // than a String... argument, because otherwise the
    // implementation of AbstractCommand<T> would be
    // more complicated.
    public void execute(String[] arguments);
}

// Interface for clients that do need to use the
// return value of a command.
public interface ValuedCommand<T> extends Command {
    public T evaluate(String[] arguments);
}

// Optional, but useful if most of your commands are ValuedCommands.
public abstract class AbstractCommand<T> implements ValuedCommand<T> {
    public void execute(String[] arguments) {
        evaluate(arguments);
    }
}

// Singleton class with utility methods.
public class Commands {
    private Commands() {} // Singleton class.

    // These are useful if you like the vararg calling style.
    public static void execute(Command cmd, String... arguments) {
        cmd.execute(arguments);
    }

    public static <T> void execute(ValuedCommand<T> cmd, String... arguments) {
        return cmd.evaluate(arguments);
    }

    // Useful if you have code that requires a ValuedCommand<?>
    // but you only have a plain Command.
    public static ValuedCommand<?> asValuedCommand(Command cmd) {
        return new VoidCommand(cmd);
    }

    private static class VoidCommand extends AbstractCommand<Void> {
        private final Command cmd;

        public VoidCommand(Command actual) {
            cmd = actual;
        }

        public Void evaluate(String[] arguments) {
            cmd.execute(arguments);
            return null;
        }
    }
}

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

Единственная причина, по которой не следует сразу использовать Void , - это все неприглядные возвращают null; утверждения, которые вам придется вставить.

4
ответ дан 3 December 2019 в 03:53
поделиться

Я бы предпочел явно использовать Void . Легко увидеть, что происходит, без участия другого класса. Было бы неплохо, если бы вы могли переопределить возврат Void с помощью void Integer с помощью int и т. Д.), Но это не приоритет.

10
ответ дан 3 December 2019 в 03:53
поделиться

Не изменяйте интерфейс: вот почему Void находится в стандартной библиотеке. До тех пор, пока все, что вызывает Команду, ожидает возврата значений NULL

И да, NULL - единственное значение, которое вы можете вернуть для Void.

Обновление 2017 г.

В течение последних нескольких лет я избегал Void как возвращаемых типов, за исключением случаев, когда речь идет об отражении. Я использовал другой шаблон, который, на мой взгляд, более явный , а избегает нулей. То есть у меня есть тип успеха, который я называю Ok , который возвращается для всех команд, таких как OP. Это очень хорошо сработало для моей команды, а также распространилось на другие команды.

public enum Ok { OK; }

public class SideEffectCommand implements Command<Ok> {
    @Override
    public Ok execute(String... args) {
        ...
        return Ok.OK; // I typically static import Ok.OK;
}
3
ответ дан 3 December 2019 в 03:53
поделиться

В вашем примере интересно использование параметризованных типов. Обычно у вас будет

interface Command<T> {
    public T execute(T someObject);
}

В вашем случае у вас будет только T в качестве возвращаемого значения. Тем не менее использование Void в этом случае - хорошее решение. Возвращаемое значение должно быть null .

2
ответ дан 3 December 2019 в 03:53
поделиться

Эта проблема не та обычная, но и не такая уж редкая ... Думаю, я видел обсуждение этого некоторое время назад, о вызываемых объектах, которые ничего не возвращают.

Я согласен с другими авторами в том, что это хорошее решение, намного лучше, чем использование Object или другого фиктивного заполнителя.

1
ответ дан 3 December 2019 в 03:53
поделиться

Мне кажется, это нормально. Как говорили другие, Void изначально был разработан для механизма отражения, но теперь он довольно часто используется в Generics для описания ситуаций, подобных вашей.

Еще лучше: Google в своей структуре GWT использует та же идея в их примерах для обратного вызова, возвращающего пустоту (пример здесь ). Я говорю: если Гугл это делает, должно быть как минимум ОК .. :)

4
ответ дан 3 December 2019 в 03:53
поделиться

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

Учтите следующее:

public class CommandMonitor {

    public static void main(String[] args)  {       
        Command<?> sec = new SideEffectCommand();       
        reportResults(sec);     
    }   

    public static void reportResults(Command<?> cmd){

        final Object results = cmd.execute("arg");
        if (results != null ) {
            System.out.println(results.getClass());
        }
    }
}

Нет ничего плохого в использовании в качестве типа шаблона, но разрешение его смешивания с реализациями для «Command » означает, что некоторые клиенты интерфейса могут не ожидать недействительного результата. Не меняя интерфейс, вы позволили реализации создать неожиданный результат.

Когда мы передаем наборы данных с помощью классов Collection, моя команда согласилась никогда никогда не возвращать null, даже если синтаксически это хорошо. Проблема заключалась в том, что классы, которые использовали возвращаемые значения, должны были постоянно проверять пустоту, чтобы предотвратить NPE. Используя приведенный выше код, вы увидите это повсюду:

    if (results != null ){

Потому что теперь есть способ узнать, действительно ли реализация имеет объект или имеет значение null. В конкретном случае, конечно, вы знаете, потому что вы знакомы с реализацией. Но как только вы начнете их агрегировать или они выйдут за пределы вашего горизонта кодирования (используются в качестве библиотеки, для дальнейшего обслуживания и т. Д.), Возникнет проблема с нулевым значением.

Затем я попробовал следующее:

public class SideEffectCommand implements Command<String> {

    @Override
    public String execute(String... args) {
        return "Side Effect";
    }

}

public class NoSideEffectCommand implements Command<Void>{
    @Override
    public Void execute(String... args) {
        return null;
    }   
}
public class CommandMonitor {

    public static void main(String[] args)  {       
        Command<?> sec = new SideEffectCommand();
        Command<?> nsec = new NoSideEffectCommand();

        reportResults(sec.execute("args"));
        reportResults(nsec.execute("args")); //Problem Child
    }   

    public static void reportResults(Object results){
        System.out.println(results.getClass());
    }

    public static void reportResults(Void results){
        System.out.println("Got nothing for you.");
    }
}

Overloading didn ' t работают, потому что второй вызов reportResults по-прежнему вызывает версию, ожидающую Object (конечно). Я подумывал перейти на

public static void reportResults(String results){

, но это проиллюстрировало корень проблемы: ваш клиентский код начинает знать детали реализации. Предполагается, что интерфейсы помогают изолировать зависимости кода, когда это возможно. Добавление их в этот момент кажется плохим дизайном.

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

Это может быть случай дырявых абстракций .

3
ответ дан 3 December 2019 в 03:53
поделиться

Что, если бы вместо интерфейса типа:

public interface Command<T> {
    T execute(String... args);
}

у вас было бы:

public interface Command<T> {
    void execute(String... args);
    T getResult();
    bool hasResult();
}

Тогда вызывающие абоненты сделали бы:

public void doSomething(Command<?> cmd) {
    cmd.execute(args);
    if(cmd.hasResult()) {
        // ... do something with cmd.getResult() ...
    }
}

Вы также можете создать интерфейс VoidCommmand, который расширяет Command, если вы вроде.

Это кажется мне самым чистым решением.

-1
ответ дан 3 December 2019 в 03:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: