« 1 2 »
Autor Zpráva
HonzaM
Profil *
Ahoj, mám trochu problém, teprve s OOP začínám a trochu jsem se zasekl. Zhruba něco takového:
class A{
protected $name;
public function getName($jmeno)
{
$this->name = $jmeno;
}
protected function Hello()
{
return "Hello".$this->name
}
}
class B{
private $class;
public function __construct(A $a)
$this->class = $a;
}
public function Write()
{
return $this->class->Hello();
}
}

Aby to ale fungovalo, musí být metoda Hello public. a to právě nechci. dědění taky nechci použít, protože potřebuju vytvořit instanci i třídy A. nějaký nápad? Děkuji
Joker
Profil
HonzaM:
Ano, přesně jak se píše, metoda Hello musí být public.
I z toho jak to je napsané (i když to je jen příklad) metoda Hello vypadá jako metoda pomocí které ta třída komunikuje s okolím, ne jako vnitřní metoda té třídy. Takže by měla být public.

Jinak metoda pojmenovaná getName proměnnou $name nevrací ale nastavuje (tzn. je to setter a ne getter), takže by se měla jmenovat setName.
HonzaM
Profil *
Jasně, to byl jenom takový příklad, psal jsem to v rychlosti, tak jsem si toho nevšiml. v té mojí třídě A jsou metody, které by nebylo dobré mít public, ale zase je využívá ta metoda B, je to začarovaný kruh...nedá se to nějak vyřešit?
Nox
Profil
HonzaM:
Jestli není problém v návrhu ... pokud máš konkrétní problém, tak je lepší to řešit konkrétně.

Private a protected metody jsou metody, které objekty používají pro vnitřní implementaci své funkčnosti, často pro zjedodušení (DRY...)
Public metody jsou naproti tomu funkčnost, kterou objekt poskytuje jiným.

Z tohoto tvůj model asi nebude úplně ok. V C++ třeba existuje tzv. friend, ale myslim že to není moc doporučované.
Mike8748
Profil
HonzaM:
dědění taky nechci použít, protože potřebuju vytvořit instanci i třídy A.
a jakej je problém pří dědění ohledně vytváření instance A ?
HonzaM
Profil *
No hele mám třídu, která vytváří formulář. metody kterým zadáváš parametry a oni vytváří inputy a checkboxy...
No a pak mám třídu která by to měla zobrazovat, jenomže v té první třídě jsou pomocný metody, které potřebuju aby byli private, jenomže zase je bude využívat i ta druhá třída...
A co kdybych teda vkládal tu zobrazovací třídu do té třídy formulář? a volal bych v ní její metody? To by ale zase byl trochu divný návrh


Mike:
No docela jo, hlásí mi to že to nejde, nějaký Fatal Error: Cannot redeclare...
Nox
Profil
Máš asi blbě zápis, každopádně...

Tak nevim, co ty pomocný metody třeba vyhodit do zvláštní třídy a používat jí v obou? Ale pořád je to lehce abstraktní...
HonzaM
Profil *
Tak už mi to dědění funguje, problém byl v tom že tam musí být include_once a ne include..jaký je v tom rozdíl?
Joker
Profil
HonzaM:
Nějak vyřešit se to určitě dá. Jak to vyřešit, to závisí na tom konkrétním kódu.
V kódu uvedeném v [#1] je podle mě správné řešení nastavit metodu Hello jako public. V jiném kódu může být jiné.

Obecně bych řekl:
• Metody pro komunikaci třídy s okolím z logiky věci musejí být veřejné (všechny vlastnosti sloužící pro komunikaci třídy s okolím dohromady dávají tzv. protokol).
• Zároveň veškerá funkčnost kterou okolí potřebuje musí být dostupná skrze protokol, neboli když má třída pro někoho něco dělat, musí na to být veřejná metoda.
• Metody pro vnitřní použití dané třídy nemají být public, ale zároveň okolí vůbec nemá co uvažovat o tom, že by je používalo.
• Pokud okolí potřebuje nějakou funkčnost a zároveň ta funkčnost je jasně vnitřní záležitost dané třídy, potřebuje se okolí hrabat ve vnitřku třídy, což je špatně a je potřeba upravit návrh.

ad dědění:
Já si nejsem jistý, že tady je to správná cesta, sice nemáme moc informací, ale jestli ty třídy reprezentují formulářový prvek a formulář, neřekl bych, že formulář je rozšířením formulářového prvku.

ad include_once: Překvapivě include_once vloží daný kód pouze jednou (tj. nevloží, pokud už byl vložen někde dříve).
HonzaM
Profil *
Joker: ta jedna třída reprezentuje všechny prvky, jsou tam metody, které vytváří inputy, checkboxy, textarea, a potomkem této třídy by měla být třída, která bude zobrazovat formulář, tam bude několik možností jak to zobrazovat.
Ale mám tu problém:
class A{
public pokus = null;
public function setPokus($text)
{
$this->pokus = $text
}

}
class B extends A
{
public function getPokus()
{
$return $this->pokus;
}
}

$classA  = new A();
$classA->setPokus("Ahoj");
$classB = new B();
echo $classB->getPokus();
Nic to nevypisuje
Nox
Profil
Pořád to vidim na [#7] a myslim že bez konkrétního kódu už víc neporadíme
Joker
Profil
HonzaM:
ta jedna třída reprezentuje všechny prvky, jsou tam metody, které vytváří inputy, checkboxy, textarea
Neznám konkrétní podmínky a záměry s daným kódem, ale nepřipadá mi to jako ideální návrh.
Ten popis vlastně definuje objekt typu „všechny možné formulářové prvky“ a formulář samotný bere jako zvláštní případ tohohle objektu. Já mám problém si to představit tímhle způsobem.
Připomíná to návrhový vzor factory, ale tam by nebyla pro každý typ prvku zvláštní metoda.

Nic to nevypisuje
Samozřejmě že ne. Nastudujte si rozdíl mezi třídou a instancí třídy.
Uvedený kód nastaví hodnotu Pokus = "Ahoj" v jedné instanci třídy A a potom se zeptá na hodnotu Pokus úplně jiné instance třídy B.
HonzaM
Profil *
No já jsem koukal na pár návrhů a nikde jsem neviděl že by se na všechno dělala zvlášt třída, třída na input, na checkbox na radio... přijde mi to trošku zbytečné, spíš jsem viděl, že byla třída Form a v ní metody Input, radio...
A taky jak by se tohle řešilo? v každé třídě by byla metoda, která by ten daný element vytvořila a druhá která vypsala? a všechny by dědili třídu form která by jenom udělala <form...></form>?
nemeja
Profil
nejsem si jisty, ale $return.. nemelo by to byt return..
Johnik
Profil
HonzaM:
Zbytečné to určitě není..., a dělá se to běžně: http://api.nette.org/2.0/namespace-Nette.Forms.Controls.html
HonzaM
Profil *
nemeja:
Mělo, psal jsem narychlo příklad a nevšiml jsem si chyby :)
Johnik:
a co bych teda měl do těch tříd dát? Jak by teda měli vypadat? to budu mít x malých tříd se dvěma metodama.
Jako přijde mi jednodušší vytvořit instanci jediné třídy a volat jenom metody, než vytvářet instance několika tříd a volat plno metod...
Je pravda že to moje řešení úplně přesně nezapadá do OOP návrhu, tedy že je všechno objekt, já mám že objekt je pouze formulář a jednotlivý elementy jsou pouze metody, ale zase je to potom na práci příjemnější


Joker:
Samozřejmě že ne. Nastudujte si rozdíl mezi třídou a instancí třídy.
Uvedený kód nastaví hodnotu Pokus = "Ahoj" v jedné instanci třídy A a potom se zeptá na hodnotu Pokus úplně jiné instance třídy B.


No tak to nepůjde v jedné třídě mít metody, kterým bych zadal parametryy formuláře a druhou třídou vypsal
Johnik
Profil
HonzaM:
Tak jestli řešíš formuláře, tak se inspiruj těmi v nette, jsou zcela správné. V OOP by se mělo dodržovat "co třída (objekt), to jedna zodpovědnost".

Obecně by formuláře měly být nějak takto:

Form - kontejner na formulářové prvky, tady klidně můžou být, vedle metody addControl (nebo addChild apod.), právě ty tvé addButton, addFileInput, ...
FormRenderer (obecně nějaký IRenderer) - vypisování formuláře (jednou renderer pro export do HTML, druhý renderer pro export do něčeho jiného, ...)

FormControl - Prvek formuláře, většinou pouze nějaká základní abstraktní implementace, která se právě rozšiřuje, například Button nebo FileInput, ...

Validator - Kdyby se šlo do důsledku, tak by validace neměla být obsažena přímo ve FormControl (a jeho odvozeninách), ale v externím objektu - validátoru
Joker
Profil
HonzaM:
a co bych teda měl do těch tříd dát? Jak by teda měli vypadat? to budu mít x malých tříd se dvěma metodama.
To záleží na potřebách projektu.
Ale už mezi těmi základními, třeba klasickým vstupním políčkem (input type="text") a výklopné pole (select) vidím hodně rozdílů; Textové pole bude mít vlastnosti jako maximální délka políčka nebo povolené znaky, které u výklopného pole nedávají smysl, výklopné pole zas bude mít třeba výčet možných hodnot a podobně.
Nemluvě o případných složitějších prvcích, třeba v ASP.NET je formulářový prvek DataGrid a vlastností má poněkud více než dvě metody.
pozn.: ASP.NET není PHP, ale zrovna tohle je podobné: Formulářový prvek, ze kterého na konci vypadne nějaké HTML. Jde o ilustraci, že ta funkčnost může být opravdu rozsáhlá.

Jako přijde mi jednodušší vytvořit instanci jediné třídy a volat jenom metody, než vytvářet instance několika tříd a volat plno metod.
Může to tak být, ale potom by ty metody měl obsahovat sám formulář, něco jako AddTextField, AddCheckbox, atd.

Je pravda že to moje řešení úplně přesně nezapadá do OOP návrhu, tedy že je všechno objekt, já mám že objekt je pouze formulář a jednotlivý elementy jsou pouze metody, ale zase je to potom na práci příjemnější
Jenže to ani nemá výhody plynoucí z OOP, kdybych si prostě vyrobil jednu funkci CreateFormField($type, $attributes), která mi vyrobí pole požadovaného typu a nastaví mu atributy podle pole které předám, bude to možná ještě jednodušší.

No tak to nepůjde v jedné třídě mít metody, kterým bych zadal parametryy formuláře a druhou třídou vypsal
Půjde, ale musely by si mezi sebou předávat data.
HonzaM
Profil *
Ok, tak dejme tomu, že udělám třídu form, třídu input, třídu select, do konstruktoru zadám name a ostatní parametry. třída form bude mít metodu start ktetá udělá <form> a metodu end která udělá </form> no a ostatním třídám dám konstruktorem parametry, nebo vlastnostma a bude tam metoda která mi vrátí hotový element...
Ted jde o to, jak to zobrazovat. V tom mém řešení to bylo dělaný pomocí pole, všechny elementy se ukládali do pole a pak tam byla metoda která to vypsala, bud normálně bez nějakýho formátování, nebo odřádkovávala, nebo se to dávalo do tabulky, ale jenom o dvou sloupcích aby byl vedle sebe label a ten element a pak na každý z elementů zvlášt metoda, která by vypsala každý zvlášt, kdybych chtěl jijné formátování, než jaké podporuje ta třída. Jak bych to řešil tady? Šlo by udělat třídu, do které by vstupovali všechny objekty a ona by to vypisovala? a hlavně jak to udělat, aby bylo možno zadat x objektů...třeba v C# je klíčové slovo param, které zajistí přidání libovolného počtu parametrů...
Omlouvám se že tady tak otravuju, ale s OOP začínám, rád se dozvím něco od zkušenějších, sice mám dost načteno, ale nestačí to...
Hlavně chci, aby to bylo na použití jednoduchý, abych se neupsal, ten můj návrh byl velmi jednoduchý na používání, ted jde o to jestli bude i tohle.
Joker
Profil
HonzaM:
Jak jsem psal, to závisí na konkrétních požadavcích toho projektu.
Ale například by to šlo tak, že prvek by měl metodu která vrátí HTML a formulář taky, přičemž formulář by měl kolekci prvků a při zavolání té metody by vytvořil formulář a v něm všechny prvky.

Případně by vypsání formuláře zařídila nějaká jiná třída, viz Johnik a FormRenderer.

Omlouvám se že tady tak otravuju, ale s OOP začínám, rád se dozvím něco od zkušenějších, sice mám dost načteno, ale nestačí to...
V pořádku, vlákna na téma „Jak co nejlépe něco navrhnout“ jsou řádově užitečnější, než „Níže je 200 řádků kódu, najděte mi tam syntaktickou chybu“.
HonzaM
Profil *
Prosím tě, ještě poslední věc, jak myslíš tu kolekci? jako že by ta třída byla schopná přijímat instance těch všech elementů a potom je vykreslit? jak se to dá prakticky udělat?
Dík
Johnik
Profil
HonzaM:
Například

private $_elements = array();

public function addElement(FormElement $element, $name, $label)
{
   $this->_elements[$name] = $element;
   return $element;
}

public render()
{
   // vypsani <form ...>
   foreach ($this->_elements as $element)
      // vypsani elementu - treba $element->render();
   // vypsani </form>
}

// jeste muzes pouzit zminovane usnadneni - tovarnicky:
public function addText($name, $label)
{
   return $this->addElement(new TextInput($name), $name, $label);
}

// ...
HonzaM
Profil *
Johnik:
Takže ta metoda render mi z pole element zobrazí jednotlivé objekty, předpokládám že v tom poli budou instance objektů, dá se nějak udělat abych mohl volat i metody? Třeba ty elementy budou mít metodu Zobraz(). můžu v tom foreach zavola $element->Zobraz() ?
Johnik
Profil
Přesně tak to je, akorát se to nejmenuje Zobraz, ale render. Metoda render je jak ve třídě Form, tak na základní třídě pro prvky FormControl. V tom příkladu je vše, přečti si to pořádně.
HonzaM
Profil *
Nějak jsem nepochopil, proč zadávat label do addText když se tam s ním nic neděje, nebylo by lepší ho dávat do konstruktoru TextInput?
A asi není možné v tom foreachu volat různé metody že ne? vždycky to musí být element->render()

Já jsem si teda udělal tento návrh:
Třída form
Nastaví methods a action
Má metody AddInput, AddTextArea...
a metodu render která to všechno vykreslí.

Třída element
měla by to být abstraktní třída které bude předkem těch tříd InputText, TextArea...
ale zatím nevím co v ní bude, nějaká rada?

A nakonec budou třídy jednotlivých elementů, v konstruktoru budou přijímat name, label a array attributes
a budou mít jedinou metodu render() která poskládá html a bude se volat v render u Form.
Jenom nevím, jak render ve formu bude poznávat, který rendery u těch tříd jsou aktivní a jak jdou za sebou.
Johnik
Profil
Už tomu rozumím, v tom případě bych udělal:

Form - přesně jak to teď máš.
abstract FormElement - tam bude právě ta metoda render. V tvém případě to může být jen rozhraní IFormElement. Je to pro čistotu, tudíž Form::render při procházení elementů má jistotu, že metoda render je na elementu definovaná - což je zajištěno tím, že Form::addElement si vynutí pouze odvozeniny FormElement (nebo IFormElement).
TextInput, TextArea, ... - rozšiřující FormElement (nebo implementující IFormElement). Přetížením (nebo definicí) metody render se zajistí správné vypsání toho elementu.

Ten $label byl myšlen tak, že se v v addElement vytvoří ještě objekt Label, který zajistí automatické spojení id (FormElement odvozenina) a for (Label) atributů. Není důležité.

Form bude elementy logicky renderovat tak, jak byly přidány. Té otázce s aktivním a neaktivním elementu nerozumím.

Další vylepšení by mohlo být zavést abstraktní třídu Html, která bude předek tříd Form a FormElement. Pak by se mohlo zjednodušit (zapouzdřit) renderování do této třídy.

class Html
{
construct($tag, $isPair) {...}
render() { return "<" . $this->tag . " " . $this->renderAttributes() ...; }
setAttribute($name, $value) {...};
getAttribute...
}

abstract class Form extends Html
{
construct() { parent::construct("form", true); $this->setAttribute("method", "post"); }
}

class FormElement extends Html {}

class TextInput extends FormElement
{
construct($name) { parent::construct("input", false); $this->setAttribute("type", "text"); $this->name =  $name ... }
}

Tohle řešení dotažené do extrému: https://github.com/johnikx/sisy.php/tree/master/sisy/forms (a navrhovaná třída HTML dotažená do extrému: https://github.com/johnikx/sisy.php/tree/master/sisy/display)
HonzaM
Profil *
No když tak na to koukám, třída HTML by mohla být předkem spousty jiných tříd, mohla by být univerzální že jo?

Johnik:
tudíž Form::render při procházení elementů má jistotu, že metoda render je na elementu definovaná - což je zajištěno tím, že Form::addElement si vynutí pouze odvozeniny FormElement (nebo IFormElement).
TextInput, TextArea, ... - rozšiřující FormElement (nebo implementující IFormElement). Přetížením (nebo definicí) metody render se zajistí správné vypsání toho elementu.

Tomuhle moc nerozumím
Johnik
Profil
Html může být předkem spousty tříd.

Kdyby jsi neprogramoval v PHP, ale v nějakém silně typovém jazyce, tak je společná základní třída (nebo rozhraní) u těch prvků je nezbytná. Jednoduše si tím vynutíš správný parametr v metodě addElement (prostě jen objekty instanceof nejakaSpolecnaTrida) a navíc poté v metodě render máš jistotu, že když zavoláš na elementu metodu render, že program neskončí chybou (prostě je to zajištěno tou společnou třídou).
HonzaM
Profil *
Johnik:
Koukal jsem to sisy a tam, když chceš použít nějakou třídu tak jenom napíšeš use, já musím psát i include aby mi to fungovalo, ale tam ne.
Například v Form.php je jenom use sisy\forms\controls\TextInput;
já bych musel napsat i include "TextInput.php"
Čím to je?
Johnik
Profil
HonzaM:
use s include nemá nic společného. Use pouze říká, že ve třídě použiju nějakou třídu -> dovolí mi psát jen TextInput namísto sisy\forms\controls\TextInput.

Jsou to jmenné prostory: http://php.net/manual/en/language.namespaces.php
A to autoloadování je udělané pomocí funkce __autoload: http://cz.php.net/manual/en/function.autoload.php. A díky tomu, že platí jmenný prostor = složka, tak loader je velice jednoduchý: https://github.com/johnikx/sisy.php/blob/master/loader.php (použití je vidět v index.php)
« 1 2 »

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: