Правильная регистрация в контексте ООП

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

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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
0
2 765
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

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

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

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

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

Ответ принят как подходящий

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

Сам не мог бы сказать лучше.

Outlaw Programmer 17.09.2008 23:32

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Bruno 19.10.2016 18:27

@Bruno В Log4J мы предоставляем различные файлы конфигурации для тестирования, например, во время тестирования он может перейти в текстовый файл или консоль для данного журнала, но при производстве он может перейти в базу данных. Я также передал регистратор в конструктор, чтобы упростить тестирование. Синглтон также работает, но становится трудно имитировать / заменять для тестов, если он становится большим (и действительно, это просто дублирует работу, которую log4j предоставляет с файлами конфигурации). Лучшая ставка - весна, но это может быть излишним, в зависимости от вашей ситуации.

Bill K 19.10.2016 19:19

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

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

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

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

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

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

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

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

удачи!

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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