Я знаю, это считается плохим
$this->laptop->getKeyboard()->getTouchpad()->getLbutton();
или же
$this->laptop->getKeyboard()->getCapslock()->isLedOn();
это объясняется как «нам не нужны тонны -> -> -> ->» — но я хотел сделать эту конструкцию физической, я имею в виду, что ее нельзя отделить. Я понимаю, что если архитектор изменится, это должно быть сделано везде, но этого не произойдет. Опять же, как обойти это?
Закон Деметры о зависимостях не -> (или точки на других языках).
Например, если у вас есть свободный интерфейс (где методы возвращают это), этот закон не применяется.
Вы хотите, чтобы ваш класс зависел от минимального количества других классов.
Если ваш класс зависит от 10 других классов, изменение любого из них может нарушить его. Сложнее понять, чем занимается ваш класс. Также сложно проверить такой класс.
Неважно, если у вас есть $field->getDependency1()->getDependency2()
или же $field->dependency1->dependency2
— ваш код по-прежнему зависит от двух других классов и знает внутреннюю структуру зависимостей1 (что он имеет внутри зависимостей2).
Вы можете решить свою проблему с скажи не спрашивай принцип.
В OOD вы не хотите использовать структуры, которые просто содержат данные. Вы хотите иметь объекты, которые знают, что делать с их полями.
Например, вы можете рефакторинг:
$oldBalance = $bank->getAccount()->getBalance();
$bank->getAccount()->setBalance($oldBalance - $amount);
Для того, чтобы:
$bank->withdraw($amount);
В банковском классе:
function withdraw($amount) {
$this->account->withdraw($amount);
}
В классе аккаунта:
function withdraw($amount) {
$this->balance = $this->balance - $amount;
}
У вас есть больше методов, но теперь код, который использует $ bank, ничего не знает о счете и его балансе. Вы можете легко протестировать этот класс, издеваясь над полем $ bank. У вас также есть более многократно используемый код.
Представьте себе этот разговор:
You: Hey Laptop, get me the I/O devices
Laptop: There you go
You: Hey IODevices, get me the keyboard
IODevices: There you go
You: Hey Keyboard, get me the touchpad
Keyboard: There you go
You: Hey Touchpad, I want to press your left button
Touchpad: Consider it done Boss!
Чувак, ты чертовски фанат электроники, или ты делаешь это для жизни — ты знаешь каждый маленький кусочек своего ноутбука! 😉
против этого:
You: Hey Laptop, I want to press left button on the touchpad
// Laptop gets the job done
Laptop: Done Boss!
Во втором разговоре, под капотом,
Laptop
называет свою зависимость IODevices
(Вам не нужно ничего знать об этом), IODevices
называет свою зависимость Keyboard
(Latop
не нужно знать об этом), Keyboard
получает свою зависимость Touchpad
(IODevices
не нужно знать об этом — ну, на самом деле это немного плохой пример, но … вы поняли), а затем вызывает pressLeftButton()
в теме.Тем не менее, вы не заботитесь о деталях, все, что вы хотите сделать, это pressLeftButton
, Вам не нужно знать, как Keyboard
а также Touchpad
связаны, что возвращается от каждого метода и т. д. У вас есть открытые интерфейсы, которые должны быть реализованы.
И это делает всех счастливыми, потому что ничто не может сломаться, когда вы замените KeyboardXyz
с KeyboardAbc
До тех пор, пока последний реализует тот же интерфейс.