Вопрос

Вот проблема, с которой я боролся с тех пор, как впервые начал изучать объектно-ориентированное программирование:как следует реализовать регистратор в "правильном" коде ООП?

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

Мы не хотим устанавливать объект logger в качестве глобальной переменной, потому что глобальные переменные - это плохо, верно?Но мы также не хотим, чтобы объект logger передавался в параметрах каждого отдельного метода, который мы вызываем в каждом отдельном объекте.

В колледже, когда я заговорил об этом с профессором, он на самом деле не смог дать мне ответа.Я понимаю, что на самом деле существуют пакеты (скажем, для Java), которые могли бы реализовать эту функциональность.Однако, что я в конечном счете ищу, так это знание о том, как правильно и ООП-способом реализовать это самому.

Это было полезно?

Решение

Ты делай хотите установить регистратор как глобальную переменную, потому что глобальные переменные являются нет плохой.По крайней мере, сами по себе они не так уж плохи.Регистратор - отличный пример правильного использования глобально доступного объекта.Прочитайте о шаблоне проектирования Singleton, если вам нужна дополнительная информация.

Другие советы

Есть несколько очень хорошо продуманных решений.Некоторые предполагают обход OO и использование другого механизма (AOP).

Ведение журнала на самом деле не слишком хорошо подходит для OO (что нормально, не все подходит).Если вам нужно реализовать это самостоятельно, я предлагаю просто создать экземпляр "Log" в верхней части каждого класса:

частный окончательный журнал = новый журнал (этот);

и тогда все ваши вызовы для ведения журнала будут тривиальными:log.print("Привет");

Что делает его намного проще в использовании, чем синглтон.

Попросите ваш регистратор выяснить, в какой класс вы переходите, и используйте это для аннотирования журнала.Поскольку затем у вас есть экземпляр log, вы можете выполнять такие действия, как:

log.addTag("Счет");

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

log4j и chainsaw - идеальное готовое решение, хотя, если вы не просто занимаетесь академической работой, используйте их.

Глобально доступный регистратор - это сложная задача для тестирования.Если вам нужно "централизованное" средство ведения журнала, создайте его при запуске программы и внедрите в классы / методы, которые нуждаются в ведении журнала.Как вы тестируете методы, которые используют что-то подобное:

public class MyLogger 
{
    public static void Log(String Message) {}
}

Как вы заменяете его макетом?

Лучше:

public interface ILog 
{
    void Log(String message);
}

public class MyLog : ILog 
{
    public void Log(String message) {}
}

Я всегда использовал шаблон Singleton для реализации объекта logging.

Вы могли бы посмотреть на синглетный паттерн.

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

Я думаю, вам следует использовать для этого AOP (аспектно-ориентированное программирование), а не ООП.

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

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

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

Тот Самый Блок приложения для ведения журнала Корпоративной библиотеки это предложение от Microsoft Pattern & Practices group является отличным примером реализации платформы ведения журнала в среде ООП.У них есть отличная документация о том, как они реализовали свой прикладной блок ведения журнала, и весь исходный код доступен для вашего собственного просмотра или модификации.

Существуют и другие подобные реализации: log4net, log4j, log4cxx

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

Я полностью за AOP вместе с log4 *.Это действительно помогло нам.Google выдал мне эта статья например.Вы можете попробовать поискать больше по этому вопросу.

(ИМХО) то, как происходит "ведение журнала", не является частью дизайна вашего решения, это скорее часть любой среды, в которой вы работаете - например, System и Calendar в Java.

Ваше "хорошее" решение - это такое, которое максимально слабо связано с какой-либо конкретной реализацией ведения журнала, поэтому подумайте об интерфейсах.Я бы проверил тропу здесь вот пример того, как Sun справилась с этим, поскольку они, вероятно, придумали довольно хороший дизайн и выложили все это так, чтобы вам было чему поучиться!

используйте статический класс, он имеет наименьшие накладные расходы и доступен из всех типов проектов в рамках простой ссылки на сборку

обратите внимание, что синглтон эквивалентен, но требует ненужного выделения

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

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

ИМХО, одного ведения журнала недостаточно, вот почему я написал СПОКОЙСТВИЕ

удачи вам!

Возможно, вставка ведения журнала прозрачным способом скорее соответствовала бы идиоме Аспектно-ориентированного программирования.Но здесь мы говорим об ОО-дизайне...

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

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

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

Я решал эту проблему в прошлом, добавляя экземпляр класса ведения журнала в базовый класс (или интерфейс, если язык это поддерживает) для классов, которым необходим доступ к ведению журнала.Когда вы что-то регистрируете, регистратор просматривает текущий стек вызовов и определяет из него вызывающий код, устанавливая надлежащие метаданные о операторе ведения журнала (исходный метод, строка кода, если она доступна, класс, который зарегистрировался, и т.д.) Таким образом, минимальное количество классов имеют регистраторы, и регистраторам не нужно специально настраивать метаданные, которые могут быть определены автоматически.

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

На самом деле, большую часть времени я использую ведение журнала на commons (я много работаю на java), но есть аспекты дизайна, которые я описал выше, которые я нахожу полезными.Преимущества наличия надежной системы ведения журнала, на отладку которой кто-то другой уже потратил значительное время, перевесили потребность в том, что можно было бы считать более чистым дизайном (это, очевидно, субъективно, особенно учитывая отсутствие подробностей в этом посте).

У меня были проблемы со статическими регистраторами, вызывающие постоянные проблемы с памятью (по крайней мере, я подумай вот в чем проблема), так что я, вероятно, скоро вернусь к регистраторам.

Чтобы избежать глобальных переменных, я предлагаю создать глобальный РЕЕСТР и зарегистрировать там свои глобальные переменные.

Для ведения журнала я предпочитаю предоставлять одноэлементный класс или класс, который предоставляет некоторые статические методы для ведения журнала.

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

Еще одним возможным решением является создание класса Log, который инкапсулирует протоколирование / хранимую процедуру.Таким образом, вы можете просто создать экземпляр new Log(); всякий раз, когда вам это нужно, без необходимости использовать синглтон.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top