Поделитесь важными примерами без связи

Допустим, вы пишете "большее" приложение и хотите регистрировать определенные ошибки в ваших классах. Теперь почти каждому классу нужен доступ к Logger.

Одним из простых решений было бы следующее (PHP, но это не имеет значения):

class SomeClass {
  public function someMethod() {
    // stuff ...
    Logger::log("something happened");
    // stuff ...
  }
}

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

"Небольшое" обновление вышеприведенного подхода будет следующим:

class SomeClass {

  private $logger;

  public function __construct(/* stuff */) {
    $this->logger = LoggerFactory::getLogger();
  }

  public function someMethod() {
    // stuff ...
    $this->logger->log("something happened");
    // stuff ...
  }
}

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

Другой подход будет использовать внедрение зависимости:

class SomeClass {

  private $logger;

  public function __construct(Logger $logger, /* stuff */) {
    $this->logger = $logger;
  }

  public function someMethod() {
    // stuff ...
    $this->logger->log("something happened");
    // stuff ...
  }
}

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

$object = new Position($this->logger, $x, $y);

Другая проблема, с которой я столкнулся, заключается в том, что Logger на самом деле не является частью Position класс как $x а также $y, Это просто утилита.

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

2 ответа

Решение

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

Я вижу два варианта здесь:

1) Вы ссылаетесь на все свои регистраторы через какой-то класс Manager и используете тот, который вам нужен на уровне класса. Этот LoggingManager должен быть известен всем классам в решении, которым требуются функции ведения журнала. Я делал это часто при работе с внешними Каркасами регистрации (например: Log4Net).

2) Или вы можете запросить регистратор во время выполнения от вышестоящего субъекта (Сервиса), который предоставит требуемый Регистратор. Использование структуры Dependancy Injection Framework или Aspect Oriented Programming в стиле класса исключило бы выбор типа регистратора (или фабрики) из самого класса.

К сожалению, я не очень разбираюсь в PHP, поэтому не могу предоставить вам пример кода. Но я нашел этот хороший пример АОП в C#: http://visualstudiomagazine.com/articles/2011/05/12/wccsp_aspect-oriented-programming.aspx

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

Один из самых распространенных сценариев использования AOP - ведение журнала, поэтому стоит посмотреть.

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

По этой ссылке вы можете посмотреть, как ведение журнала может быть реализовано с использованием postsharp, платформы C# AOP

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