Я новичок в программировании, но старался усвоить хорошие методы проектирования. Мой вопрос связан с тем, как справиться с подобной ситуацией if-statement, поскольку она, кажется, нарушает Don't Repeat Yourself.

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

public bool Process()
{
    if (ErrorLog == null)
    {
        //Metadata analysis code that may write errors

        if (ErrorLog == null)
            return true;
        else
            PublishErrorLog();
        return false;
    } 
    else
        PublishErrorLog();
    return false;
}
0
Masasar 6 Янв 2016 в 19:04

3 ответа

Лучший ответ

Последняя функция может выглядеть так просто:

public bool Process()
{
    if (hasError())
        return false;
    //Metadata analysis code that may write errors
    //Note that error log may change here
    return !hasError(); //updated by juharr
}

Объяснение:

Код, который вы представляете, может быть не совсем таким же, если строка с //metadata analysis действительно может изменить состояние ErrorLog.

Шаг упрощения 1. Единичный цикл "если-еще"

Однако, видя ваш вложенный цикл, я бы предпочел упростить обработку и чтение кодов, выполнив что-то вроде этого

public bool Process()
{
    if (ErrorLog != null){
        PublishErrorLog();
        return false;
    }
        //Metadata analysis code that may write errors
       //Note that error log may change here

    if (ErrorLog != null){
        PublishErrorLog();
        return false;
    }

    return true;
}

По сути, вместо того, чтобы делать вложенные if-else, вы делаете простой оператор, который может быть возвращен первым. Затем вы возвращаетесь, если он удовлетворен, иначе вы продолжаете.

Таким образом, ваш код превращается в единый условный цикл - без вложенного цикла.

Шаг упрощения 2. Журнал ошибок + имеет комбинированную функцию ошибок

Вы можете еще больше улучшить приведенный выше код, учитывая, что ваш шаблон регистрации ошибок такой же, вы можете создать такую ​​функцию

bool hasError(){
    if (ErrorLog != null){
        PublishErrorLog();
        return true;
    }
    return false; //no error, can continue
}

Окончательный код

Тогда функция Process будет выглядеть так:

public bool Process()
{
    if (hasError())
        return false;
    //Metadata analysis code that may write errors
    //Note that error log may change here
    return !hasError(); //updated by juharr
}

Очень лаконично. И вы можете повторить шаблон в другом месте.

3
Ian 6 Янв 2016 в 16:26

Похоже, вы используете свойство ErrorLog, чтобы сигнализировать о действительности вашего соединения. Если ErrorLog является строкой, как я понял из вашего вопроса, у меня был бы конкретный способ узнать, действительно ли соединение или нет, и не полагаться на недействительность журнала.

Например

public bool Process()
{
    if (HasValidConnection)
    {
        //Metadata analysis code that may write errors
    }

    if (ErrorLog == null)
    {
        // no errors establishing the connection neither processing metadata
        return true;
    }
    else
        PublishErrorLog();
    return false;
}
1
Fede 6 Янв 2016 в 16:19

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

public bool Process()
{
    if (ErrorLog != null)
        //At this point, the PublishErrorLog should have already been called.
        return false;

    try
    {
        // Do Metadata analysis that may throw errors
    }
    catch (ErrorLogException e)
    {
        PublishErrorLog()
        return false;
    }
    return true;
}

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

РЕДАКТИРОВАТЬ:

Как указал Арон, это можно сделать, вообще не имея ErrorLog в качестве члена класса. Информация журнала может храниться в самом исключении. Блок catch может выглядеть так:

catch (ErrorLogException e)
{
    var logMessage = e.logMessage;
    PublishErrorLog(logMessage);
    return false;
}
2
Omada 6 Янв 2016 в 16:32