2015-03-01 7 views
0

Мне не удалось найти соответствующий заголовок, так как это не простая проблема. Я попытаюсь объяснить. У меня есть класс, ответственный за сообщение об ошибках, чьи методы в основном обертывают несколько способов сообщения об ошибке. Например, у меня есть метод failTest:дизайн сообщения об ошибках

public static void failTest(Logger log, Exception e, String message, boolean reportToES, String esTestPath, String esTestSet, String esTestInstance) 
{ 
log.error(e, message); 
someExternalErrorReportingService(reportToES, esTestPath,esTestSet,esTestInstance); 
Assert.fail(e,message); 
} 

И я называю этот метод отчетности ошибок во многих, многих местах и ​​это не кажется хорошей практикой (слишком много параметров, трудно следовать их порядок и т.д.), чтобы просто называть его параметрами es * каждый раз, потому что они не меняются очень часто, поэтому их можно настроить один раз, а затем повторно использовать. И я придумал эту версию

public static void failTest(Logger log, Exception e, String message) 
{//same body 
} 
And then added method to set up es* parameters 
setES(boolean reportToES, String esTestPath, String esTestSet, String esTestInstance) 
{ 
this.reportToES = reportToES; 
this.esTestPath = esTestPath; 
this.esTestSet = esTestSet; 
this.esTestInstance=esTestInstance; 
} 

и, конечно, добавили эти переменные экземпляра выше. И только теперь я могу сформулировать проблему: теперь, если я хочу использовать этот класс сообщений об ошибках, мне нужно сначала создать экземпляр и установить поля es *. Проблема в том, что мне часто приходится использовать отчет об ошибках в классе утилиты, который может быть статичным, но теперь, с моим изменением выше, мне нужно создать его экземпляр и настроить класс сообщений об ошибках, чтобы установить поля es * перед Я вызываю failTest(). В заключение мне не нравится это решение либо потому, что я больше не могу использовать статические классы полезности, и, кроме того, некоторые классы полезности уже используются статическим образом, поэтому их нельзя реорганизовать на нестатические и в конечном итоге будут использоваться статически , иногда экземпляр. Итак, вопрос в том, видите ли вы лучшее решение, чтобы упростить вызов функции failTest() в служебных классах? Чтобы дать вам пример, у нас есть клиент, который настраивает класс отчетов об ошибках и устанавливают свои эсы * поля Этот клиент вызывает метод утилит Utility.doSomething

public static doSomething(reportToES, esTestPath, esTestSet, esTestInstance) 
{ 
try{ 
methodThatThrowsFatalException() 
} 
catch(Exception e){ 
failTest(log, e, "Some smart message",reportToES, esTestPath, esTestSet, esTestInstance); 
} 
} 

Теперь для того, чтобы уменьшить число из параметров мы можем просто добавить setErrorReportingInstance в класс Utility, , а затем в клиенте создать экземпляр Utility, а затем утилиту INSTAN. setErrorReportingInstance (configuredErrorReportingInstance). И йоЗотеЬЫпд становится:

public static doSomethingRefactored() 
{ 
try{ 
methodThatThrowsFatalException() 
} 
catch(Exception e){ 
errorReportingInstance.failTest(log, e, "Some smart message"); 
} 
} 

Что не хорошо, с моей точки зрения, является то, что: 1. Я усложнили использование утилиты. Теперь я должен убедиться, что он создан, прежде чем использовать его. Это неудобно, когда у вас много полезности, таких как классы. 2. Я не могу создавать статические методы в Утилите, если мне нужно сделать отчет об ошибках в их реализации. 3. Методы, которые уже используются как статические, будут оставаться с параметрами es * в их сигнатуре (из-за обратной совместимости). Поэтому у меня будут такие же методы класса, как doSomething, а также такие методы, как doSomethingRefactored. 4. Я создал зависимость между классами полезности и сообщениями об ошибках, поэтому у меня возникла проблема, когда мне нужно проверить методы утилиты

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

Подробнее: На самом деле клиент много TestNG случаев тестов: Так первый у меня был:

class TestClass1 
{ 
static final boolean REPORT_TO_ES="true", 
static final String ES_TEST_PATH="somePath", //and so on for the others 
@Test 
{ 
Utility1.doSomething(REPORT_TO_ES,ES_TEST_PATH,ES_TEST_SET,... 
Utility2.doSomethingElse(REPORT_TO_ES,ES_TEST_PATH,ES_TEST_SET,... 
Utility3.doSomethingMoreUseful(REPORT_TO_ES,ES_TEST_PATH,ES_TEST_SET,... 
Utility4.doSomethingSomething(REPORT_TO_ES,ES_TEST_PATH,ES_TEST_SET,... 
} 

И тогда я хотел бы попробовать избавиться от вызова doSomethings с ES * Значением установки их один раз на экземпляр ErrorReporter (так что я бы также сделал ErrorReporter нестатическим).

class TestClass1 
{ 
private ErrorReporter errorReporter = new ErrorReporter(); 
errorReporter.setReportToEs(true); 
errorReporter.setEsTestPath("somePath");//and so on 
Utility1 utility1Instance = new Utility1(); 
utility1Instance.setErrorReporter(errorReporter); 
Utility2 utility1Instance = new Utility2(); 
utility2Instance.setErrorReporter(errorReporter); 
@Test 
{ 
utility1Instance.doSomething(); 
utility2Instance.doSomethingElse(); 
... 
+0

Объедините все параметры Es в объект Es. Вы можете передать это в doSomething(). – user1879313

+0

Если утилита используется только для тестирования (ваш последний комментарий подсказывает это), тогда сделать Утилиту самим объектом Es. Непонятно, почему вы предпочитаете статические методы в этом случае. Должен признаться, мне трудно понять общую картину. Почему бы не опубликовать полный источник? – user1879313

+0

es переменные - это устаревший код. Мы не знаем сейчас, будем ли мы их держать или нет. Вот почему я хочу держать их в центральном месте, чтобы они были полностью удалены, если мы решили, что они им никогда не понадобятся. Но, как всегда, у нас не может быть всего этого, поэтому объединение параметров Es в объект Es кажется лучшим решением, имеющим 4 значения – coss

ответ

0

Право на ваш вопрос должно быть «Статический беспорядок».

Посмотрите, как работают настоящие регистраторы, и вы можете получить некоторые идеи. Log4J и Slf4j являются уважаемыми. Вам нужно управлять всеми вашими статическими переменными. Вы можете создать класс Logger, который инкапсулирует данные ES и делает реальную работу лесозаготовок:

// Does the real work of logging. 
class Logger { 
    public Logger(all of your es data) 
    public fail(String msg) // Logs msg 
} 

Тогда вам нужен статический сбор этих лесозаготовителей, на которые ссылаются именем (я предполагаю, что у вас есть более чем один набор данных эс). Это дает вам центральное место для поиска регистраторов. Работает, если вы находитесь в статическом методе или где-то еще. Статическая коллекция идет внутри объекта LogFactory

class LogFactory { 
    private static Map<String, Logger> loggers ... 
    public static Logger get(String name) ... 
} 

Вот ваш статический метод с использованием нового регистратора:

public static doSomething() { 
    try { 
    methodThatThrowsFatalException() 
    } 
    catch(Exception e){ 
    LogFactory.get("Util").failTest(e, "Some smart message"); 
    } 
} 

Я хотел бы добавить ясный или сбросить метод LogFactory, так что у вас есть шанс написания JUnit проверяет ваш код. По той же причине я бы написал NullLogger (в этом случае вам может понадобиться вытащить интерфейс, который могут реализовать NullLogger и EsLogger.

Вам нужно решить, как добавить Loggers в LogFactory. в вашем основном классе. Сопротивляйтесь соблазну сделать это в статическом инициализаторе.

LogFactory также можно записать так, чтобы он хранил коллекцию, а не статическую коллекцию. Затем вы просто сохраняете статическую ссылку (Singleton). Просто имейте в виду, что вам нужно будет очистить Синглтон, чтобы сделать возможным модульное тестирование.

Удачи.

+0

Спасибо за ответ. Проблема с вашим решением заключается в том, что класс утилиты (который имеет метод doSomething()) не знает, какой регистратор должен получить (например, «Util»). Только клиент знает, какие значения es являются подходящими, поэтому класс утилиты все равно должен быть создан для того, чтобы быть уверенным в значении имени регистратора или значений es. Простите, я раньше не упоминал об этом ограничении. – coss

+0

Помогите мне понять. Вам нужно установить некоторые глобальные данные, прежде чем вы вызове doSomething(), чтобы функция failTest() работала правильно? В сущности, вы используете кучу для обхода стека? – user1879313

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