2008-09-17 5 views
8

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

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

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

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

ответ

13

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

+1

Не мог бы лучше сказать это. – 2008-09-17 19:32:09

0

Вы можете посмотреть шаблон Singleton.

0

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

1

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

+1

Кто бы ни проголосовал: почему? – 2008-10-29 15:35:31

0

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

0

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

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

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

0

Enterprise Library Logging Application Block, который исходит из шаблона Microsoft & Практическая группа - отличный пример реализации фреймворка регистрации в среде ООП. У них есть отличная документация о том, как они внедрили свой блок приложений ведения журнала, и весь исходный код доступен для вашего собственного обзора или модификации.

Есть и другие подобные реализации: log4net, log4j, log4cxx

Они, как они реализованы в библиотеке Enterprise Logging Application Block должен иметь статический Logger класс с несколькими различными методами, которые фактически выполняют работу журнала. Если бы вы рассматривали шаблоны, это, вероятно, было бы одним из лучших применений шаблона Singleton.

4

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

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

приватный финал log = new Log (this);

и все ваши вызовы регистрации являются тривиальными: log.print («Эй»);

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

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

log.addTag («Билл»);

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

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

+0

Поступая таким образом, вы не сможете издеваться над журналом при тестировании объекта.Это означает, что если регистратор, например, регистрируется в службе третьей стороны, каждый раз, когда вы тестируете этот объект, вы получите эту строку журнала где-нибудь. Я думаю, что в этом случае сохранение регистратора в контейнере было бы лучшей идеей, так как вы всегда можете заменить экземпляр контейнера (singleton) этого объекта для фиктивного Logger. – Bruno 2016-10-19 15:27:08

0

Я все для АОП вместе с log4 *. Это действительно помогло нам. Например, Google дал мне this article. Вы можете попытаться найти больше по этому вопросу.

0

(IMHO) Как происходит «регистрация», это не часть вашего дизайна решения, это больше часть любой среды, в которой вы работаете, - как System и Calendar на Java.

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

0

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

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

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

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

ИМХО в одиночку недостаточно, поэтому я написал CALM

удачи!

0

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

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

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

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

0

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

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

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

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

2

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

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) {} 
} 
0

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

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

0

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

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

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

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