Я пытаюсь оттачивать свои навыки программирования и натолкнулся на неприятную проблему, которую, вероятно, лучше всего объяснить на примере:
Допустим, я создаю microCMS на PHP. Эта microCMS имеет класс Router, который отвечает за маршрутизацию. Он также содержит URI и дополнительные параметры, извлеченные из него.
class Router{
private $uri;
private $params;
...
public function getRoute(){ ... }
...
public function getParams(){
return $this->params;
}
...
}
У меня также есть Front Controller, которому я передаю новый объект Router (). Пока все хорошо, я могу получить доступ к дополнительным параметрам в моем Front Controller (через $router->getParams();
).
class FrontController{
private $controller;
private $view;
public function __construct(Router $router){
$route = $router->getRoute();
...
$params = $router->getParams(); //Yay, I can get to the params here!
...
$this->view = new View($route->getModel());
...
}
Теперь вот где это становится сложным для меня. Этот Front Controller создает представление. Я хотел бы, чтобы это представление также имело доступ к функциям маршрутизатора (например, чтобы можно было получить параметры URI из него).
class View{
public function output(){
//But how do I access the Router's params here...?
}
}
Первое, самое простое решение, кажется, состоит в том, чтобы превратить маршрутизатор в одноэлементный объект или просто сделать функцию статичной и просто вызвать Router::getParams()
… Но это нет, нет, потому что анти-паттерны.
Второе, очевидное решение — передать мой экземпляр Router конструктору View. Я хочу избежать этого из-за страха, что мой конструктор станет гениальным в будущем. Я не уверен, сколько других классов мне нужно будет получить доступ из представления, как это, и я не хочу, чтобы они излишне загромождали его конструктор. Этот страх оправдан?
Другое решение было бы использовать сервисный локатор и вызвать что-то вроде $serviceLocator->getRouter()
по-моему. Но это, видимо, тоже анти-паттерн.
Так в чем же решение? Или что-то не так с архитектурой моей CMS?
FrontController
использования Внедрение зависимости, который считается лучшим способом справиться с этим. Поскольку вы передаете экземпляр класса напрямую, вы не создаете global
проблема, присущая синглетонам.
Страх, что ваш View
Конструктор будет раздут, это необоснованно. Если вам нужна зависимость, то вам нужно внедрить ее куда-нибудь. Тебе не нужно делать это внутри своего конструктора. Вы всегда можете сделать такую функцию, как
public function setRouter(Router $router) {
$this->router = $router;
}
И впрысните это так.
Если ваш класс действительно раздут, вам нужно преобразовать его в подклассы.
Других решений пока нет …