Objektově orientované myšlení
Bez objektů už si dnes programování nedokážu ani představit. Tento článek je jen rychlým úvodem k objektovému programování. Dle mého názoru u objektového programování jde především o způsob myšlení.
Důležitý je především způsob myšlení a přístup k řešení problémů. Základem je abstrakce konkrétních věcí, tedy jejich zjednodušení na samou podstatu. Vymezení okruhu vlastností a funkčnosti, která je pro daný objekt charakteristická a pro náš účel stěžejní.
Některé úkoly, které má aplikace řešit mohou být pro člověka na pochopení příliš složité. Každá aplikace řeší nějakou reálnou funkčnost a pokud nevím kudy do toho, snažím se rozebrat danou úlohu na dílčí části, ty abstrahovat a definovat jejich dílčí funkčnosti a vlastnosti. Pokud respektuji funkčností a vlastnostmi objektu reálný svět, tak jak to doopravdy funguje, nemohu udělat chybu a nakonec jednotlivé části budou tvořit funkční celek.
V objektovém programování takový abstraktní prvek nazýváme třída. Třída má své vlastnosti a metody. Vlastnosti mohou být např. velikost, barva, váha, objem apod. Metody pak mohou s těmito vlastnostmi manipulovat, provádět výpočty, tisknout sestavy atd.
Příklad: Mým úkolem je vytvořit modul na kreslení grafů.
Modul můžeme chápat jako množinu prvků (tříd, komplexů tříd, podsystémů, částí aplikace atd.), které zajišťují určitou funkčnost. Graf je reálný objekt a je tvořen dílčími součástmi, v našem případě budeme řešit bodový graf. Skládá se logicky z těchto objektů: bodový graf, body, osy, barvy a text.
Nejmenším objektem je bod, jeho vlastnosti jsou souřadnice na osách x a y, případně barva bodu (vysvětlím v dalším příkladu) atd. Třídu která ho reprezentuje vytvoříme takto:
- class Point {
- public $x, $y, $color;
- /* Základní metodou je konstruktor, je to funkce označená __construct, nebo funkce pojmenovaná stejně jako název objektu Point, tato funkce vytváří instanci objektu */
- public function __construct($x, $y, $color=new Color(0,255,0)) {
- $this->x=$x;
- $this->y=$y;
- $this->y=$color;
- }
- }
- $a=new Point(1,5); // vytvoření instance a
- $b=new Point(2,10); // vytvoření instance b
Třída je jakýsi vzor objektu, na základě něho můžeme vytvářet instance třídy, což je už konkrétní objekt. Konkrétních objektů můžeme mít kolik chceme. V příkladu jsou vytvořeny dvě instance a, b. První z nich a je bod se souřadnicemi na ose x=1 a na ose y=5. V našem příkladu je důležité použití slova $this, znamená to, že přistupujeme k instanci, tedy že hodnotu $x přirazujeme instanci, která funkci volala, tedy ke konkrétnímu objektu. Další použití jak přistupovat k vlastnostem třídy je self, tím přistupujeme ke třídě jako celku, nezávisle na instancích, tedy ke statické vlastnosti. Pokud nastavíme vlastnost pomocí self, např.: self::$staticVariable = 1;, pak bude vlastnost staticVariable stejná pro všechny instance i pro ty v budoucnu vytvořené. Přistupujeme pomocí operátoru dvojité dvojtečky ::, který se nazývá Paamayim Nekudotayim. Pomocí self přistupujeme uvnitř třídy, ale můžeme použít např. Point::$staticVariable=1;.
Dalším objektem, který si vytvoříme je barva, definujeme ji v konstruktoru a to zadáním podle modelu RGB, celočíselný typ vyjadřující červenou, zelenou, modrou.
- class Color {
- public $red, $green, $blue;
- public function __construct($red, $green, $blue) {
- $this->red=$red;
- $this->green=$green;
- $this->blue=$blue;
- }
- public function getColor() {
- ...
- }
- }
- $color1=new Color(150,200,250);
- $color2=new Color(100,115,200);
Funkce getColor pak vrací definici barvy pro GD knihovnu na kreslení obrázků, pokud je výstupem grafu obrázek, ale můžeme volit i jiné výstupy, například výstup pro javascript, který graf vykreslí nebo xml, pak by se nám mohla hodit funkce která vrací barvu ve tvaru #000000, tedy převádí RGB hodnoty na hex.
Podobně bychom mohli stavět i další třídy jako je Chart, Axis, Text a PointChart. Metodou Chart bude například vypočítat vhodné rozmezí popisků (jejich vzdálenost od sebe) pro osy, cílem PointChart bude především fungovat jako zásobník, tedy bude obsahovat pole a funkci, která přiřadí jednotlivé body do tohoto pole, zároveň bude dědit všechny metody a vlastnosti od Chart. Dále metodu která vytvoří a uloží obrázek grafu, vygeneruje xml nebo data potřebná pro javascript, který graf vykreslí.
- class PointChart extends Chart {
- public $points;
- public function __construct() { }
- public function addPoint($point) {
- $this->points[]=$point;
- }
- ...
- ...
- }
Konečná práce s modulem pak může vypadat např. takto:
- $chart = new PointChart();
- for ($i=1; $i<10; $i++) {
- $chart->addPoint(new Point($i, rand(0,100)));
- }
- $chart->setTitle("Popisek grafu");
- $chart->save("graf.gif");
Na první pohled spatřuji výhodu OOP v čitelnosti kódu a ve změně způsobu myšlení na rozdíl od procedurálního programování.
Přednosti OOP
1. Čitelnost kódu
Výše zmíněný příklad mi příjde přirozenější a pro člověka čitelnější než změť desítky funkcí a kódu, který by musel programátor kopírovat a znovu vkládat do všech souborů, které se snaží vytvořit nějaký graf. Kód je zapsán tak, že programátor dokáže intuitivně pochopit jak kód funguje aniž by musel hledat další souvislosti nebo pročítat rozsáhlý manuál.
2. Způsob myšlení
Každý člověk má nějakou mentální hranici k pochopení složitého komplexu funkčnosti. OOP přístup umožňuje rozložit komplex na dílčí části a umožnit tak řešit je odděleně, usnadňuje tak mnohem více práci v týmu, kdy se každý člověk může podílet na jiné části, aniž by byli na sobě významně závislí. Stačí jen dopředu definovat objekty, které budeme používat a co od nich chceme.
3. Znovupoužitelnost
Spousty programátorů nedoceňuje tuto vlastnost. Nějak zbastlit programový kód, aby fungoval jak chci je možná zprvu rychlejší a méně náročné než vytvořit objektový model, ale z dlouhodobějšího hlediska se může vyplatit druhý přístup. Už jen příklad s grafy mluví sám za sebe, vykreslit graf může být otázka 5 řádků, a implementace do jiných aplikací nebo jiných skriptů je velice snadná.
4. Skládání objektů
Odkazovat na jiné objekty a využívat jejich funkce se nazývá skládání objektů. Umožňuje nám to kooperaci různých objektů a tím vznikají celky objektů. Objekt Chart bude nejspíše obsahovat referenci na objekt Text, který umí psát do obrázku. Pomocí této reference mohu přikázat objektu text, aby vepsal titulek grafu na horní okraj obrázku. Výhodou je, že objekt Chart vůbec nemusí umět psát do obrázku a snadno tak můžeme přejít na generování grafů do pdf, pokud změníme metody objektu Text a nemusíme se starat, kdo všechno provádí zápis do obrázku.
5. Dědičnost (generalizace)
Probíhá zápisem class PointChart extends Chart { ... }, znamená to, že PointChart je potomkem třídy Chart a tak dědí všechny její metody i vlastnosti. Například třída Chart by měla mít funkce co kreslí osy a ty budou společné jak pro bodový graf tak pro sloupcový. K rodiči můžeme přistupovat pomocí parent::.
- class HashColor extends Color {
- public function __construct($hash="000000") {
- $red = hexdec(substr($hex,0,2));
- $green = hexdec(substr($hex,2,2));
- $blue = hexdec(substr($hex,4,2));
- parent::__construct($red, $green, $blue);
- }
- }
V tomto příkladě jsme použili dědičnosti a přetížení. Nově tedy můžeme používat barvy v hex zápisu, aniž by to mělo vliv na chod celého systému, rozšířili jsme systém o použití hex barev. Například bílý bod v grafu můžeme zapsat takto new Point(10, 20, new HashColor("FFFFFF"));. Třída HashColor udělá nejprve to, že zdědí od třídy Color všechny metody a vlastnosti, poté převede hex barvu na RGB a volá konstruktor rodiče (třídu Chart) s parametry, které rodič očekává.
6. Překrytí (overriding)
Překrytí využíváme při dědičnosti. Potomek sdědí všechny metody a vlastnosti, ale můžeme si vybrat kterou překryjeme, tedy vyměníme její obsah a nadále se bude nová metoda vykonávat podle potomka. Jako v předchozím příkladě s dědičností.
7. Viditelnost
Tento termín znamená, že můžeme jednotlivým funkcím nebo metodám definovat jejich viditelnost pro okolní svět (ostatní objekty). Tedy metody jsou buď dostupné jen uvnitř třídy nebo jsou dostupné navenek. Definujeme to klíčovými slovy private, protected, public (viditelná pro své okolí), více se dozvíte v manuálu. Umožňujeme tak objektům spravovat jejich práva a role uvnitř systému, zoodpovědnost za procesy a odstínění od vlivů jiných objektů.
8. Zapouzdření
Znamená, že funkčnost a způsob provedení procesů je uzavřen uvnitř třídy. Objekty nám poskytují jakési rozhraní, API, které umožňuje jiným objektům komunikovat mezi sebou, aniž by věděli co se děje uvnitř. Definujeme funkce objektu a říkáme ostatním co daný objekt umí a jak mu říci, aby to či ono udělal, už však nemusíme řešit jakým způsobem to udělá. Např. objekt Chart umí přidat objekt Point na osy x a y nebo umí říci objektu Text, aby vypsal na určené místo nějaký text. Objekt Chart neví a nestará se o to jak to Text udělá, nestará se o to jestli píše text do pdf nebo obrázku.
Závěrem
Tento článek neměl být návodem jak se naučit OOP, v tomto případě doporučuji řadu článků na intervalu nebo se inspirovat přímo z manuálu, ale reakcí na časté dotazy typu: proč používat OOP, k čemu je to dobré, vždyť se dá bez toho obejít, jen to zbytečně zdržuje jak lidi tak stroje.
podobné články
| 07.03.2008 | Nedocenitelná funkce __autoload v OOP | (8%) |
komentáře
RSS Komentáře
No ide o to, ze overloading v „skutocnych“ (povodnych) OOP jazykoch umoznuje definovat dve metody s rovnakym menom. To ktora metoda sa zavola, urcuje jej signatura (zoznam a typy argumentov). Rychly priklad:
public int checkUser(String username) {
// over na zaklade mena }
public int checkUser(int id) {
// over na zaklade userID }
Volanie by potom bolo: isValid = nejakyobjekt.checkUser(„Dano“); isValid = nejakyobjekt.checkUser(3258);
Bohuzial PHP toto vraj nikdy nebude podporovat, pretoze je to vagne typovany jazyk (nejde kontrolovat typ predanych argumentov). Okrem toho sa daju v C++ pretazit aj operatory, nejaky typek vraj dokazal pretazit aj operator ciarky.
No a k tej definicii zapuzdrenia: Vo vseobecnosti ide o to, ze trieda akoby poskytovala akesi API, rozhranie pomocou ktoreho pracujem s objektom. Nevidim (a ani ma to nezaujima) co sa deje pod kapotou, ale pomocou tohoto API (zapuzdrenia) som schopny vykonat svoju pracu. prikladom moze byt praca s kniznicou fpdf:
$pdf=new FPDF(); $pdf->AddPage(); $pdf->SetFont(‚Arial‘,‚B‘,16); $pdf->Cell(40,10,‚Hello World!‘); $pdf->Output();
Ja neviem ako tie metody pracuju, ale pomocou rozhrania som schopny vyrobit PDF dokument „in no time“. A ak by sa kniznica aktualizovala, staci zachovat rozhranie, pod kapotou sa moze vymenit komplet kod (napr. optimalizacia), ale ja ako koncovy programator sa o to nemusim zaujimat, lebo vyuzivam vyhody zapuzdrenia.
To o com ste pisal vy, je skvor viditelnost.
- Blog je o PHP, tedy o overloading v JAVE vím, ale to sem nepatří
- Zapouzdření je možná smíchané s viditelností, ale řekl bych, že zkráceně jsem řekl to samé, nevidím v tom, že by někdo byl uveden v omyl nebo si přečetl něco co je nesmysl, přečtěte celý článek, ne jen nadpisy
- Co se týče toho kde použít objekt a kde funkci to bych neřešil, co programátor to jiný přístup
- článek je úvodní k OOP v PHP a tuhle úlohu dle mého splnil
to neni overloading ale overriding Misstatement má pravdu overloading je prekrývanie metód. vždy sa zavolá taká metóda ktorá má parametre vhodného typu. overriding je možnosť prepísať virtuálnu metódu z rodičovskej triedy. v PHP a v Jave sú všetky metódy automaticky virtuálne vo väčšine ostatnývch jazykov(C#, C++, Object Pascal) sa ale ako virtuálne musia označiť keywordom virtual a pri overridingu sa používa keyword override. taktiež si autor mýli vlastnosti a atribúty. vlastnosti (property) v jazyku PHP neexistujú (aj keď sa dajú emulovať pomocou magických metód __get a __set) to čo autor nazýva vlastnosťami sa v skutočnosti nazýva atribúty. a v PHP(a jave) je k ním odporúčané pristupovať cez Gettery a Settery, v C#, Delphi, VB a Pythone sa k atribútom pristupuje cez vlastnosti.
Máte pravdu, bod 6. je poněkud zmateně napsaný, kombinuje překrytí a přetížení (celý odstavec kombinuje přetížení a překrytí), nicméně v PHP něco jako přetížení dost dobře udělat nejde.
Tedy 29.1.2010 update bodu 6. který pojednává pouze o překrytí, přetížení je o jiných jazycích než je PHP. Bohužel v době psaní článku je to celkem rozšířený nešvar (pro články o PHP) a tak najdete podobných článků více.
Co se týče atributů vs. vlastnosti zkuste rozvést jaký je v tom rozdíl.



S tou vasou definiciou pretazovania by vas v C++ alebo Jave vytahali za usi. Aj definicia zapuzdrenia nie je presna. Okrem toho je modelovy priklad az moc rozkuskovany. Osobne by som graf generoval pomocou jedinej triedy, vsetky ostatne elemeny (bod, farba) by som riesil volanim metod.