Поделитесь важными примерами без связи
Допустим, вы пишете "большее" приложение и хотите регистрировать определенные ошибки в ваших классах. Теперь почти каждому классу нужен доступ к 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