Předávání porměnných mezi objekty – Java – Fórum – Programujte.com
 x   TIP: Přetáhni ikonu na hlavní panel pro připnutí webu

Předávání porměnných mezi objekty – Java – Fórum – Programujte.comPředávání porměnných mezi objekty – Java – Fórum – Programujte.com

 

21. 8. 2015   #1
-
0
-

Dobré ráno,

Při psaní bakalářské práce jsem narazil na problém, jehož příčinou je pravděpodobně moje neznalost relativně základních programovacích technik v Javě.

Problém je následující. Hlavní třída je GUI, které obsahuje různé proměnné a metody - nezvěme ji Svet. Druhá třída je Process. Ta má představovat virtuální organismu a opět má některé proměnné, které má každý organismus své vlastní, ale zároveň potřebuji, aby jsem se z objektu Process mohl dostat na určité proměnné objektu typu Svet.

Jelikož jsem začínal programovat až na vysoké škole a to v Cčku, napadly mě gettery. V tom případě bych ale nějakým způsobem musel předávat referenci na instanci Sveta.

To je tedy základní struktura programu a já bych se rád zeptal, jestli je v tomhle případě očividné, kde dělám chybu, popřípadě jak tuto záležitost elegantně vyřešit bez použití statických proměnných popřípadě statických metod?

Děkuji všem za všechny tipy a rady.

Nahlásit jako SPAM
IP: 165.72.200.–
Petr
~ Anonymní uživatel
746 příspěvků
21. 8. 2015   #2
-
+1
-
Zajímavé

Ahoj,

prvně bych si na tvém místě položil otázku jestli může existovat více než jeden svět, tedy jestli lze předpokládat že v budoucnu bude existovat více než jedna instance třídy svět pokud ano, pokud odpověď zní ne, pak bych si dovolil napsat to celé staticky, pokud tu existuje určitá pochybnost, že bude více světů v budoucnu tak bych to napsal jako normální třídu ale použil bych singleton pattern. Já osobně jsem za druhou variantu, protože nikdy nevíš co bude, přijde nějaký trouba s tím, že chce víc než jeden Svet a budeš to celé přepisovat.

import java.util.ArrayList;
import java.util.List;

public final class Svet {
    //staticke promenne, existuji pouze jednou v ramci tridy Svet
    private static Svet singleton;

    //nasledujici promenne budou existovat pro kazdou instanci Sveta
    private List<Process> procesy; //tady si budes uchovavat list procesu vytvorenych ve svete

    /**
     * Konstruktor
     * zde lze provest nejakou inicializaci
     * protoze je konstruktor private nemuze nikdo jiny vytvorit instanci Sveta
     */
    private Svet() {
        procesy = new ArrayList<>();
    }

    /**
     * Staticka metoda ktera se nevola na instanci ale na tride samotne
     */
    public static Svet getInstance() {
        /* tohle by tu teoreticky nemuselo byt a mohlo by se to inicializovat primo v te promenne (private static Svet singleton = new Svet();),
           nicmene tento zpusob inicializace dava vetsi volnost v tom jak Svet vytvoris
           dalsi vyhodou "lazy" inicializace je to, ze obcas nektere class loadery (cast JVM ktera natahuje tridy a inicializuje jejoch staticke casti)
           se mohou chovat nestandardne a ve chvili kdy si myslis ze uz to je nainicializovane to ve skutecnosti nainicializovane neni
           
           pokud by existovalo vice instanci pak by asi bylo vhodne presunout spravu instanci tridy Svet do nejake jine tridy (pouzit factory pattern)
        */
        if (singleton == null) {
            singleton = new Svet();
        }

        return singleton;
    }

    /**
     * Tato metoda se vola na instanci tridy Svet (tedy na samotnem objektu)
     */
    public void metoda() {
        System.out.println("Metoda sveta");
    }

    /**
     * Vytvori novy proces ve svete, ulozi si referenci do interniho listu a vrati tuto referenci
     */
    public Process vytvorProces(/*tady by mohly byt nejake parametry*/) { //mohlo by to vracet i void zalezi na tom co s tim procesem chces delat
        Process newProcess = new Process();
        procesy.add(newProcess);
        return newProcess;
    }

    /**
     * Vrati seznam procesu v tomto svete
     */
    public List<Process> getProcessList() {
        return procesy;
    }
}


public class Process {
    public Process() {
        // pokud by existovalo vice svetu pak bych predal referenci na Svet jako parametr tohoto konstruktoru
        // ulozil ji do privatni promenne a pak ke svetu pristupoval pomoci teto reference
    }

    public void test() {
        Svet.getInstance().metoda(); //pokud existuje jen jeden svet muzes na to jit takto, stejnym zpusobem muzes volat nejaky getter na objektu typu Svet
    }
}
Nahlásit jako SPAM
IP: 83.240.112.–
21. 8. 2015   #3
-
0
-

#2 Petr
Svět bude určitě vždy jeden. Jen jsem si myslel, že pokud se něco snažím dělat podle standardů OOP, tak bych se měl statickým metodám a statickým proměnným vyhnout.

Statický přístup už mě jinak také napadl. Ještě jsem našel tady na webu poznámku:

-> Můžete předat objekt do metody a poté volat jeho metody.

Nebylo by to také jedno z možných řešení mého problému?

Nahlásit jako SPAM
IP: 165.72.200.–
Petr
~ Anonymní uživatel
746 příspěvků
21. 8. 2015   #4
-
0
-

#3 Viracochi
statické proměnné a metody se normálně používají v celé řadě případů, nemusíš z nich mít strach, technicky když ti class loader zavede třídu do paměti tak vytvoří speciální objekt, který je singleton (existuje jen jeden v rámci class loaderu) a v tomto objektu drží veškeré informace o třídě včetně těch statických věcí, takže ono to není až zas tak statické jak by se mohlo zdát :)

Problém se statickými proměnnými a metodami je trochu jiný a sice v rozšiřitelnosti kódu a v nemožnosti použití dalších výhod OOP (rozhraní, polymorfismus atd.).

"Můžete předat objekt do metody a poté volat jeho metody."

To je technicky to co jsem měl na mysli komentářem

// pokud by existovalo vice svetu pak bych predal referenci na Svet jako parametr tohoto konstruktoru 
// ulozil ji do privatni promenne a pak ke svetu pristupoval pomoci teto reference

můžeš jakékoli metodě tedy i konstruktoru předat referenci na instanci objektu a pak tímto způsobem přistupovat k této instanci a jejím public metodám (přes gettery i k jejím interním proměnným).

Nahlásit jako SPAM
IP: 83.240.112.–
21. 8. 2015   #5
-
0
-

#4 Petr
Dobře, díky za pomoc! Hodně jsi mi pomohl   

Nahlásit jako SPAM
IP: 165.72.200.–
Kit+15
Guru
21. 8. 2015   #6
-
+1
-
Zajímavé

#3 Viracochi
Statické proměnné a singletony se nepoužívají, protože se obtížně testují. Také proto, že nemusí existovat jen jeden Svět.

Běžně se vazby mezi objekty předávají přes tzv. Dependency Injection. Nejčastěji tak, že objekt použiji jako parametr konstruktoru druhého objektu.

V bakalářce bych se vůbec nesnažil statiku používat, mohla by ti celou práci shodit.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:207:e...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
21. 8. 2015   #7
-
0
-

#6 Kit
Tohle také zkusím jako jedno řešení. Myslíš tím něco jako tohle?

public Process(int id, int pc, int parent, Svet partOf){
        this.id = id;
        this.pc = pc;
        this.parent = parent;
        this.partOf = partOf;
        
        registry = new char[partOf.v_registrySize];
}
Nahlásit jako SPAM
IP: 165.72.200.–
Petr
~ Anonymní uživatel
746 příspěvků
21. 8. 2015   #8
-
0
-

#7 Viracochi
Ano tak nějak to může být, jen pozor na new char[partOf.v_registrySize], prostá pole jsou sice trochu rychlejší než kolekce ale nejsou tak blbuvzdorná.

#6 Kit
statické proměnné se běžně používají a to i ve velkých projektech, já osobně jsem například nedávno potřeboval counter aktivních JMS consumer instancí konkrétní třídy, tak jsem na to použil static volatile proměnnou. Řešit to pomocí DI by se to dalo, ale bylo by s tím mnohem více práce a byl by to celkem slušný overkill na to co jsem potřeboval. A kdyby jsi chtěl náhodou namítat, že to je netestovatelné tak ano je, ale proto, že to běží ve více threadech a takový kód se už v základu dost dobře testovat nedá (minimálně ne v unit testu).
Bakalářku mu to neshodí, pokud to dokáže obhájit a i kdyby shodilo tak bych se kvůli tomu moc netrápil, protože pánové na univerzitách jsou dost často trochu mimo realitu (bez urážky), namítají jak to neodpovídá OOP konvencím a když se jich člověk zeptá jak by to rychle a efektivně vyřešili tak nad jednoduchou věcí spekulují dva týdny a pak vypotí něco neefektiního a nepoužitelného (takové jsou mé praktické zkušenosti s lidmi, kteří nikdy nedělali projekt v praxi, kde jsou nějaké termíny a limity).

Nahlásit jako SPAM
IP: 83.240.112.–
Kit+15
Guru
21. 8. 2015   #9
-
0
-

#8 Petr
Myslíš takhle? 

public class VolatileExample {

    public volatile static int counter = 0;

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new MyThread();
        Thread t2 = new MyThread();
        t1.start();
        t2.start();
        Thread.sleep(1000);
        System.out.println(counter);
    }
}

class MyThread extends Thread {

    @Override
    public void run() {
        for(int i = 0; i < 10000; i++){
            VolatileExample.counter++;
        }
    }
}

Jsem zvědav, jestli ti z toho vyleze těch 20000. Možná na jednojádrovém procesoru.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:207:e...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Kit+15
Guru
21. 8. 2015   #10
-
0
-

#7 Viracochi
Na můj vkus to vypadá hodně podivně a mám problém se v tom vyznat, ale snad to DI vystihuje. Objekt "registry" mi do toho vůbec nepasuje a sám bych se takové konstrukci určitě vyhnul.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:207:e...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
21. 8. 2015   #11
-
0
-

#10 Kit
registry[] je jen pole o velikosti, kterou udává proměnná té první třída.

Nahlásit jako SPAM
IP: 165.72.200.–
Kit+15
Guru
21. 8. 2015   #12
-
0
-

#11 Viracochi
To chápu, jen se z názvu "registry" poněkud osypávám. Silně mi to připomíná jeden antipattern.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:207:e...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Petr
~ Anonymní uživatel
746 příspěvků
21. 8. 2015   #13
-
0
-

#9 Kit
ne, s inkrementaci neni problem, protoze tu dela jen jeden thread a nedochazi k ni pokud probiha dekrementace, jedina synchronizace probiha pri dekrementaci a vypada to nejak takto:

int instancesActive = consumersAlive;
                if (instancesActive > 1) {
                    synchronized (MQTranscodingConsumer.class) {
                        instancesActive = consumersAlive;
                        if (instancesActive > 1) { //double check is here to prevent unnecessary locking
                            consumersAlive--;
                            break;
                        }
                    }
                }

kde consumersAlive je static volatile a je to uvnitr cyklu (proto ten break a double check)

Kdyby jsi ve svem prikladu pouzil misto int AtomicInteger tak ti to tech 20 000 da vzdy a nebo to dat do synchronized bloku nebo metody. To co jsem myslel tim, ze to je netestovatelne je to, ze jednou ten test projde a podruhe nemusi, podle toho jak ty vlakna pobezi. Takze vysledek takoveho testu je neprukazny.

Nahlásit jako SPAM
IP: 83.240.112.–
Kit+15
Guru
21. 8. 2015   #14
-
0
-

#13 Petr
Pokud test někdy projde a někdy ne, je průkazné, že je v aplikaci něco špatně.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:207:e...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
Petr
~ Anonymní uživatel
746 příspěvků
21. 8. 2015   #15
-
0
-

#14 Kit
To je ten nejlepsi pripad, ale muze se stat, ze ti ten test nespadne nikdy a presto to bude nahodne padat v produkcnim prostredi, protoze tam je jina zatez, jine prostredi atd.

Nahlásit jako SPAM
IP: 83.240.112.–
Kit+15
Guru
21. 8. 2015   #16
-
0
-

#15 Petr
Nikdy nevěř testům, které neselžou. Pokud jednotka prochází testem, ale v produkci selhává, je chybný test a musí se opravit.

Nahlásit jako SPAM
IP: 2a00:1028:83a0:37a6:207:e...–
Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
ondrej39+1
Věrný člen
21. 8. 2015   #17
-
0
-

#1 Viracochi
Co ti schází je třetí objekt, na němž budou záviset oba objekty Svět a Proces.

Pak je další otázka, co přesně ten tvůj objekt Proces od světa potřebuje, bez implementace se to nedá odhadnout, ale je možné, že máš návrh úplně celý špatně.

Nahlásit jako SPAM
IP: 79.141.243.–
Inject all the dependencies!
Zjistit počet nových příspěvků

Přidej příspěvek

Toto téma je starší jak čtvrt roku – přidej svůj příspěvek jen tehdy, máš-li k tématu opravdu co říct!

Ano, opravdu chci reagovat → zobrazí formulář pro přidání příspěvku

×Vložení zdrojáku

×Vložení obrázku

Vložit URL obrázku Vybrat obrázek na disku
Vlož URL adresu obrázku:
Klikni a vyber obrázek z počítače:

×Vložení videa

Aktuálně jsou podporována videa ze serverů YouTube, Vimeo a Dailymotion.
×
 
Podporujeme Gravatara.
Zadej URL adresu Avatara (40 x 40 px) nebo emailovou adresu pro použití Gravatara.
Email nikam neukládáme, po získání Gravatara je zahozen.
-
Pravidla pro psaní příspěvků, používej diakritiku. ENTER pro nový odstavec, SHIFT + ENTER pro nový řádek.
Sledovat nové příspěvky (pouze pro přihlášené)
Sleduj vlákno a v případě přidání nového příspěvku o tom budeš vědět mezi prvními.
Reaguješ na příspěvek:

Uživatelé prohlížející si toto vlákno

Uživatelé on-line: 0 registrovaných, 4 hosté

Moderátoři diskuze

 

Hostujeme u Českého hostingu       ISSN 1801-1586       ⇡ Nahoru Webtea.cz logo © 20032024 Programujte.com
Zasadilo a pěstuje Webtea.cz, šéfredaktor Lukáš Churý