PHP OOP :: запутаться в классе Factory и передавать объекты конструкторам - PullRequest
1 голос
/ 06 января 2011

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

class Factory {

public $sessionId;
public $config;
public $lib;

function __construct() {
    $this->getSessionId();
}

function getSessionId() {
    if (isset($_COOKIE['sk'])) {
        $this->sessionId = trim($_COOKIE['sk']);
    } else {
        $sm = $this->createSessionManager();
        $this->sessionId = trim($sm->getNewKey());
        setcookie("sk", $this->sessionId, time() + 3600 * 3, "/");
        setcookie("vb", 0, 0, "/");
    }

}

function createBasket() {
    $t = $this->createTicket();
    $co = $this->createContribution();
    $cfg = $this->createConfig();
    $basket = new Basket($t, $co, $cfg);
    return $basket;
}

function createTicket() {
     $sm = $this->createSessionManager();
    $cfg = $this->createConfig();
    $ticket = new Ticket($this->sessionId, $sm, $cfg);
    return $ticket;
}

.... }

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

function __autoload($class_name) {
    include 'classes/' . $class_name . '.class.php';
}

$factory = new Factory;

$performance = $factory->createPerformance();
$pno = (isset($_GET['pno']) ? $_GET['pno'] : 0);
print $performance->displayHtmlListing($pno);

Мой другой вопрос / проблема связана с тем, как я предотвращаю ситуацию «catch 22», когда objectA требует objectB, который - в редких случаях - будет нуждаться в objectA.

Пример в классе Factory:

function createParser() {
    $am = $this->createApiManager();
    $parser = new Parser($am);
    return $parser;
}

Объект синтаксического анализатора передается объектом в конструктор для удовлетворения его зависимостей в бизнес-логике. Его работа заключается в чтении запросов на файлы, и, если выполняется определенное условие, ему нужно захватить объект $ am (APIManager) и запустить запрос к API. Проблема в том, что APIManager пропускает все запросы через объект Parser, и я не могу легко удалить зависимость от Parser без нарушения бизнес-правил или добавления избыточного условного кода.

Хотите знать, есть ли у кого-нибудь мысли о том, как обойти эту проблему?

Спасибо, Джеймс

UPDATE:

Дополнительная информация о проблеме зависимости:

ApiManager.caller () - его задача - перейти к URL-адресу API, отправить переменные GET и получить результаты.

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

Часть ответственности вызывающей стороны () заключается в проверке вызовов API. Если определенное условие выполнено, необходимо остановить его и вызвать SessionManager.getNewSession (), который переходит к тому же API и извлекает значение. Только после этого можно выполнить исходный запрос (в вызывающей стороне ()).

Проблема в том, что SessionManager.getNewSession () также использует caller ().

1 Ответ

3 голосов
/ 06 января 2011

Это только ИМХО, но большая доля классов с именами, содержащими "manager", "context", "parser" и т. Д., Является запахом кода.Я не говорю, что такого рода классы обязательно неправильны - конечно, практически в каждом приложении они есть.Но подумайте - парсер это то, что у вас есть, или анализирует то, что делает объект?Есть ли настоящий парень с названием «Менеджер API»?Он общается с менеджером сеансов и спрашивает вас о ваших отчетах TPS?И т.д.

Подумайте о дизайне вашего класса - я не говорю, что он «неправильный», как есть - потому что я его не видел и в любом случае это субъективно - но ваши классы моделируют объекты реального мираИли они моделируют действия, которые могут быть выполнены на объектах?Или, что еще хуже, они моделируют какой-то произвольный рабочий процесс?У всех ваших классов четко определены обязанности, и они не пытаются делать сумасшедшие вещи, которые не являются их делом?

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

Обновление в ответ на обновление Джеймса

ApiManager.caller () - его работа состоит в том, чтобы переходить к URL-адресу API, отправлять переменные GET и получать результаты.

Одна из идей ООП состоит в том, что классы представляют сущности (существительные), а методы представляют действия (глаголы).ApiManager здесь есть сущность (вроде абстрактной, но мы пойдем с ней), но caller() не является действием - то есть вы не можете "вызвать" что-то.Вы могли бы, однако, call() что-то - я думаю, в контексте ApiManager это "вызовет" API.Я знаю, что это всего лишь две маленькие буквы, но это существенно меняет представление о том, что делает ApiManager.

Этот метод caller () используется почти всеми классами (возможно, это хорошая причина дляэто быть в суперклассе и расширять классы, которые в этом нуждаются?1029 *

Часть обязанности вызывающей стороны () - проверять, какие вызовы API выполняются.Если определенное условие выполнено, необходимо остановить его и вызвать SessionManager.getNewSession (), который переходит к тому же API и извлекает значение.Только после того, как это будет выполнено, исходный запрос (в функции caller ()) может быть выполнен.

Одна проблема заключается в том, что caller() не должен нести ответственность, потому что это должно быть действие (например, * 1035).*), ничего.Действия не могут иметь обязанности.Нужно просто что-то сделать, желательно что-то простое.В соответствии с идеей ApiManager как вещи и call() как действия, которое выполняет ApiManager, ниже приведен пример очень простого минимума того, как я могу ожидать, что ApiManager будет работать:Вы заметите, что все методы в классе выше являются действиями, они все что-то делают.Замедление в торте состоит в том, что больше нет необходимости беспокоиться о внедрении зависимостей для SessionManager, потому что он больше не существует!В конце концов, сеанс API - это то, о чем должен знать только ApiManager, не так ли?:)

...