Идеята на този OOP принцип е да знаеш предварително даден обект какво може да прави като функционалност, и просто да извикваш на готово тази функционалност. А не предварително да го питаш „можеш ли да свършиш това. И ако да, свърши го.“
Казваш „направи това“ и даденият обект вече сам решава дали и как да го направи.
Как точно програмно?
Няма значение, по принцип говоря. Може да е например, с проверяване на стойността на пропърти, с извикване на метод на даденият клас…
Но това проверяване на пропъртита (asking, „питането“ дали можеш да го свършиш) не трябва да става „отвън“, а вътре в класа, тоест – чрез негов метод.
Демек, разсъждавайте на пинципа, че всички пропъртита на даденият клас НЕ са public.
Защо да не са public?
Не че ще свърши светът ако са public, но по принцип, с оглед на data encapsulation, е по-добре данновата част на класа да НЕ е public.
Демек, не го питай първо „можеш ли да свършиш това“, като му използваш пропъртитата, защото това най-малкото значи, че въпросните пропъртита трябва да са public. Което значи, че намаляваш капсулацията, въпреки че можеш да го сториш и през „getters“…
Просто му кажи направи това или онова, и нека той, обектът, да си проверява вътрешно, дали може, иска или трябва да го направи това въпросното нещо.
Или например, да имаш даден огромен обект, в който например с IF-ове да са заложени различни функционалности, и ти да му викаш даден метод и чак тогава да проверяваш коя от всичките функционалности по-точно, да му извикаш.
Демек, можем да имаме огромен обект Животно, в който да имаме метод doSound() в който да проверяваме куче ли е, котка ли е, лъв ли е, кандидат-депутат в предизборна кампания ли е…. и тогава въпросното Животно да издава съответният си свой звук.
Демек:
if ($animal->type === 'dog') { echo 'bau bau'; } elseif ($animal->type === 'cat') { echo 'miau miau'; } ....
a по-скоро:
$animal->doSound();
като обектът $animal ще е обект от клас Kуче, клас Котка, клас Кандидат-депутат в предизборна кампания… и прочее Животни.
Демек, вместо първо да го питаме „що за животно си“, и тогава „аха, куче си – лай тогава“, „аха, котка си – мяукай тогава“ и т.н…. можем и да имаме отделни класове, наследяващи Животно, като например клас Куче, клас Котка и т.н… и да му казваме „doSound()“.
Искаш да нахраниш Животното, би било то от най-нисшето, до най-висшето?
ОК, но всяко животно яде определен тип храна. Тревопасните – растения, хищниците – месо…, програмистите – бира и хамбургери….
Също, преди да нахраниш даденото животно, то трябва да е гладно. Но за да определиш дали е гладно, зависи от самото животно. Всяко си има свои критерии. Ето още една „per-animal“ специфичност…. Която трябва да се отдели в класът, който е за самото животно. А не с IF-ове да се проверява кое животно е, че тогава дали е гладно….
Демек, викаш Kуче->eat() или Koтка->eat(), Програмист->eat()…, и вече в конкретният eat() метод на съответният клас, се решава дали даденото Куче, Котка, Програмист… е гладен, по свой си начин. Per animal…
Kaзваш му „яж“, и то да си решава дали да яде или не, и какво да яде.
Демек, не питай даденият обект „можеш ли да свършиш това“.
Кажи му да го свърши и нека той сам реши дали може и трябва, и иска да го свърши.
Цялата работа е да не се използват пропъртита отвън за разни проверки дали да свършим това или онова, защото по принцип е добре данновата част на класа (пропъртитата) да са private/protected, а да казваме на обекта на класа „свърши еди си какво“ и той да си знае сам.
Без да те интересува the internal state of the object. Не питай обекта за данните му, кажи му какво да прави. И нека той си знае сам работата.
Rather than asking an object for data and acting on that data, we should instead tell an object what to do
Литература: