OOP - melyik a helyes?

Fórumok

Adott egy oldObject es egy newObject (mindketto instanceof MyClass. oldObjectnek ha van egy property-je, elvesszuk tole, es atadjuk newObjectnek (tehat vagy mindkettobe write-olunk vagy egyikbe sem)

Melyik a helyes velemenyetek szerint?


// oldObject methodjakent
$oldObject->givePropToNewObject($newObject);

es/vagy


// newObject methodjakent
$newObject->takePropFromOldObject($oldObject);

es/vagy


// static methodkent
MyClass::movePropFromObjectToObject($oldObject, $newObject);

?

Hozzászólások

Koncepcionálisan egyik sem tűnik jónak :)

Az elso nem hiszem, hogy jo lenne (most nem tudom melyik principle, de nem tunik helyesnek).

A masodik mar jobban nez ki.

Harmadik eseten static method call van, az Javaban bad practice (nehez mockolni), de ez PHP, szoval nem tudom.

Mi lenne, ha a static helyett egy factory-d lenne?


$newObject = MyClass::createObject($oldObject);

?

Ez utobbi jobban olvashato, rogton latszik, hogy mi az uj object, nincs kimeneti parameter, ami jo, stb.

Jogos, azt nem vettem figyelembe.

A konvenciok, principle-k onmagukban is ellent mondanak egymasnak sokszor, szoval ez inkabb a fejlesztonek guideline, nem szentiras :)

Viszont ha nem createObject() a fv neve, hanem mittudomen transferProperty(), a peldamban, az szerintem elegsegesen jo lehet.

Nem tudom megmagyarazni, de valahogy jobbnak tunik atvenni valamit, mint atadni. Nem mellesleg a 2. peldanal a newObject van elol, szoval a kod olvasasakor egyertelmubb, hogy melyik az "igazi" object. A static callos, output parameterest, ugyan C orokseg, de nem eroltetnem. Engem az oruletbe kerget, ha bele kell masznom a kodba, hogy megertsem mi tortenik.

Sajnos nem talalom azt a cikket, nagyon jol leirta a funkcionalis programozas alapjat, marpedig azt, hogy a bemeneti parameterek fuggvenye a kimenet, mindig, determinisztikusan. Ugyan OOP-ben vagyunk, de mas paradigmakbol jo atvenni a jo otleteket :)

Mar nem birom editalni, de tegyuk fel, hogy a fuggvenyhivaskor oldObjectnek es newObjectnek is private membere valtozik, amire (okkal) nincs semmilyen public setter. Tehat nem egy uj class "MyClassManager" fogja ezt megoldani.

A pelda PHP-s, de Javaban is erdekel pl., hogy melyik a helyes.

Nem tudom mit probalsz elerni, de erzesre a megoldas az immutable objektumok teren keresendo. Ha tenyleg _mindketto_ valtozik, akkor Javaban teheted oket azonos csomagba es akkor hozzafersz a package-private adattagokhoz, de jo esellyel ez tervezesi hibara utal mert a fuggvenynek velhetoleg lesz mellekhatasa amire a fuggveny neve nem utal. (Egy create nevu fuggvenytol nem varnam azt, hogy a regi objektumban modosit barmit is.)

Kicsit konkretabb problemaleiras kellene, nem csak egy absztrakt pelda.

--
Pásztor János
Sole Proprietor @ Opsbears | Refactor Zone

Egy olyan peldat tudok most elkepzelni, hogy A objektumnak van egy elado biciklije, amit B megvesz, igy A is valtozik meg B is. Ilyen esetben nem az objektumok vegzik a muveleteket egymason, hanem egy 3dik kulso fel. Tipikusan az ilyen domain/dto objektumoknal minimalizalni kell az uzleti logikat, hiszen azok csak adatokat tarolnak, igy a levonas hozzaadas movelet az az uzleti logika resze. Midegy, hogy Javrol vagy PHProl van szo, ezz OOP.

Amennyiben 2 service layer kozott van ilyen relacio, az tervezesi hiba, mert azok nem allitgatjak egymas propertijeit.

-
Go konkurencia kezelés gyorstalpaló

A biciklis elados pelda eleg kozel jart.

Ezenfelul a valaszokbol rajottem, hogy amit en terveztem kodot, ott nem futottam volna ilyen problemaba. Itt egy taknyolt megoldast kellett tovabbtaknyolni, ahol ez ebben a formaban merult fel. (Bonyolult lenne elmagyarazni miert, de ne gondoljatok egy tul jo kodra, attol meg, hogy tele volt a forras class-okkal, nem eppen volt objektumorientalt :P )

Nem baj az, nem vagy egyedul regi rendszerekkel, csak arra figyelj hogy mindig kicsit szebben hagyd ott a kodot mint amikor nekikezdtel. Lehet lapos hulyesegnek tunik, de ha eleget gyakorolja az ember, a vegen altalaban egy eleg tisztesseges rendszer jon ki belole.

--
Pásztor János
Sole Proprietor @ Opsbears | Refactor Zone

Szerintem mindhárom példa procedurális megoldás, OOP-ben ez úgy nézne ki hogy van egymásra referenciájuk belül és hozzáférnek ahhoz ami szükséges.

Ebbol lesz a vad kaosz :) Mert ha sima dto-k akkor ott nem kell, hogy tudjanak egymasrol. De ha valami uzleti logikat inteznek, akkor sosem lehetsz benne biztos, hogy hogyan viselkedik a cucc, hiszen barmikor megvaltozhat a mukodese (abba bele se menjunk, ha mondjuk multi thread akarod pocogtetni). Szoval erdemes elvinni immutable iranyba a dolgot, es minden viselkedes valtozaskor uj peldanyt gyartani.

-
Go konkurencia kezelés gyorstalpaló

Igen, ha a példa EJB3-as konténerektben zajlik és az átadás aszinkron SOAP hívás valamilyen 3rd party queue-n keresztül és a két POJO-ról ami tartalmazza az adatot nem tudunk semmi determinisztikusat mondani, akkor vad káosz 2 év múlva amikor 6 másik ember próbálja az új üzleti logika által okozott incidenseket megoldani.

De ha ügyesen elolvasod mégegyszer a szerző kérdését akkor azt kérdezte OOP szemlélettel két Foo ojjektum hogy is csinálja ezt.

Nezd ha ez valami 1 szemelyes hobbiprojekt, akkor vegulis mindegy, hogy hogy csinalja nem? Amire ki szeretnek lyukadni, hogy a kerdezo azt kerdezte, hogy egy ilyen problemat, hogyan lehet oop szemlelettel megoldani, es nem hiszem, hogy azt kene neki "tanitanunk", hogy hannyon bele minel tobb kereszthivatkozast a kodjaba, mert vegulis fordul meg mukodik is. Nem kell ahhoz EJB kontener, hogy megfelelo retegekre szetdarabold az alkalmazasod, es minimalizald vagy legalabbis lokalizald a side effecteket.

-
Go konkurencia kezelés gyorstalpaló

Azt kérdezte elméletben mi a helyes OOP, te meg ráhúztad a saját tapasztalatod kontextusát. Amiben igazad lenne ha egy valós problémát próbálnánk itt megoldani nem pedig 3 sornyi Foo kód lenne a posztban.

Az hogy számodra a dependency injection témaköre keresztbehányás pedig téged minősít.

"pedig téged minősít" az meg teged minosit, hogy minositgetsz itt barkit, es szemelyeskedsz te bunko. Tetelezzuk fel, hogy te nem tudsz elrugaszkodni a mareknyi kodtol, es nem tudsz olyan megoldast adni egy teoretikus kerdesre, ami jol skalazodik? Akkor ez most teged is minosit? Te komolyan azt gondolod, hogy a kerdezonek nincs fogalma a referencia szerinti atadasrol, es nincs tisztaban azzal, hogy ha van referencia, akkor azon keresztul meg tudja valtoztatni az objektum allapotat? Az altalad javasolt alpari megoldasra magatol is rajott, ahhoz nem kell valami sok esz. Arrol nem is beszelve, ha egymasra tarolnak hivatkozast, akkor azt mar peldanyositaskor be kell allitani, melyikbe huzod be a masikat, ha oda vissza kell kapcsolat, akkor korkorosen behuzod oket? Mi van ha 100 kapcsolat van? Probalj meg elszakadni a helloworld szinttol, es javasolj valami olyan dolgot ami a foobar-on kivul massal is mukodik.

-
Go konkurencia kezelés gyorstalpaló

Nem latom, a javaslatod mitol lenne OOP, minek kell a ket osztalynak foltetlenul tudnia, hogy egy bizonyos adat a masik tipusban lelheto fel, vagy hogy a masik tipus ojjektuma letezik egyaltalan. OOP nem arrol szol, hogy mindent mindennel osszedrautozunk.

Szerk: ok, beneztem, itt MyClass ket peldanyarol van szo. Mondjuk akkor sem ertem, hogy miert kene a peldanyoknak foltetlenul tudniuk egymas letezeserol egy adat megosztasa vegett. Persze, lehet ertelme, csak OOP szerintem nem kovetelne ezt meg alapbol.

----------------------
"ONE OF THESE DAYS I'M GOING TO CUT YOU INTO LITTLE PIECES!!!$E$%#$#%^*^"
--> YouTube csatornám

Nem biztos, hogy egyáltalán API metódust csinálnék ebből.

Ha pl. van egy fa adatstruktúrád, amiben vannak csomópontok, és ezen a fán illetve a csomópontokon bizonyos műveleteket végzel, lehet olyan művelet, ami több csomópontot módosít egyszerre. Ilyenkor én csak a fa osztályt és annak a fő műveleteit (addNode, removeNode, balance, stb.) ajánlanám ki, az egyes csomópontok mezőinek a módosítgatása mind privát, és külön privát metódus se feltétlenül kell rá, ha olyan egyszerű, mint pl. egy mező módosítása.

Vagy ha van egy bankszámla osztályod, és egyikről másikra utalsz pénzt, tuti nem így fog kinézni a publikus API, mint amit írtál, hanem lesz egy tranzakció manager osztály vagy valami, ami megkapja, hogy honnan-hova-mennyit, és ő majd felépíti és módosítgatja a bankszámla objektumokat a saját privát implementációjában.

Általánosságban szerintem legjobb az immutable value object, ami önmagában sok gondot megold, és publikus API-n is ki lehet ajánlani nyugodtan, neki saját logikája nincs. Írható-olvasható objektumokkal már vigyázni kell, ebből kétfélét tudok elképzelni. Az egyik az olyan, amit gyakorlatilag nem lehet elrontani, pl. egy lista, ezt lehet rétegek között passzolgatni, van benne publikus tag/privát tag/némi logika, de itt fontos, hogy nem beszélget másik objektumokkal (mert akkor lenne furcsa mellékhatása, el lehetne rontani), és itt is jobb, ha immutable. A másik, aminek ugyan minden tagja publikus, de nincs benne logika, és nincs kiajánlva sem, egy API dolgozik rajta belül.

Esetleg lehetne egy-két interface a történetben:

CanBeOwned -- valami, aminek van/lehet gazdája, pl bicikli
metódusok: getOwner, setOwner

CanBeOwnerOf (CanBeOwned object) -- valaki, aki gazdája lehet egy ilyennek
metódusok: gotObject, lostObject

TransferObject (CanBeOwned object, CanBeOwnerOf(object) from, CanBeOwnerOf(object) to) -- átadás

Mit értesz az alatt, hogy elvesszük a propertyt és átadjuk a másiknak?
A propertyk halmaza változik, vagy a propertyk halmaza ugyanaz marad, csak épp az értékek módosulnak? old adott propertyjének értéke null lesz, a new propertyjének értéke meg kitöltődik?
Előbbi esetben meg nem mondható, hogy mindkettő instanceof Myclass.

nem biztos, hogy sokat bonyolitanam es lehet nem tanultam a kulonbozo elvekrol sokat, de ahogy szoktam:
$newObject->setPropertyValami($oldObject->getPropertyValami());
aztjonapot.
amugy meg ha ez c# lenne
ValamiObject oldObject = ....
ValamiObject newObject = new ValamiObject();
...
newObject.Valami = oldObject.Valami;

ami meg felmerul itt szerintem az az, hogy ezek tenyleges ertekek vagy csak referenciak egy objectre, mert akkor nem biztos, hogy az = jo
hanem mondjuk a clone kell neked, de ez meg mar messzire vezet es nem tudom mi a cel vele, de sima int-nel nem sokat szorakoznek.
es mint tudjuk a c#ban csak nyelvi konnyedseg a newObject.Valami mint property ez javaban es mashol igy jelenik meg newObject->getValami() es newObject->setValami(var valami)

szoval a legkozelebbi jo megoldas szerintem a hozzaszolasokbol, a bal oldalon van ami kapja es jobb oldalon ami adja
ez olvashato

szepnap

Szerintem tulbonyolitod a dolgot. Kezdve azzal, hogy az egesz OOP koncepciot erosen el-erodalta a dependency injection es a funkcionalis programozas felivelese. Ma mar senki se csinal bonyi design pattern-eket, mert a tobbseguk obsolete lett azota.

Amit en szoktam csinalni es IMHO a legjobb: szeparalni az adatot es a logikat. Az adat class -ban csak adat legyen (ez lehet immutable is ekkor, az a legtisztabb), mig a kulonbozo logic class-ok vegzik a muveleteket az adaton. Ez utobbiak egymast egymasnak DI-zik igeny szerint. Az adat class-ok meg a kulonbozo DI contexteket is felvehetnek (global, session, request).

Ilyenkor az adat class tiszta (en getter/settert se rakok bele, csak public final field-eket), a logic meg siman keszit uj adat class instance-t. A fenti kerdes tehat moot, mert siman igy nezne ki:

new = logic.copyProperty(new, old);
logic.removeProperty(old);