Avatar billede amews_aj Nybegynder
27. august 2010 - 15:49 Der er 29 kommentarer og
1 løsning

Static vs accessor/mutator

Hej,

Hvis man nu har en class "MySuperClass" og en række subclasses "MySubClass1" "MySubClass2" ... "MySubClassN".
Derudover haves en "PrimaryClass" som opretter x antal objekter af de forskellige subclasses til MySuperClass.
Disse subclasses skal så tilgå samme information, fx en score.

Hvordan vil det mest hensigtsmæssigt laves?

Løsning 1:
Lav en static instansvariabel i "MySuperClass" der indeholder den delte information. Alle subclasses kan herved læse/opdatere. (Bemærk ingen brug af tråde, så burde ikke være interferens problemer).

Løsning 2:
Lav private instansvariabel i PrimaryClass, og en tilhørende accessor og mutator method. Ved oprettelse af objekter af de forskellige subclasses til MySuperClass fra PrimaryClass, sendes en reference (via "this") til PrimaryClass. Via denne reference kan subclasses så bruger get/set method til at tilgå den delte information.


Umiddelbar er løsning 1 jo langt den simpleste, men jeg mener at have hørt at man oftest gerne vil undgå brug af static da man mister fordele fra OOP.

1. Hvilken løsning er at foretrække, og hvorfor?
2. Hvornår vil man gerne undgå static? At dele informationer via static er vel først problematisk når objekter fra forskellige tråde skal tilgå informationen?
Avatar billede arne_v Ekspert
27. august 2010 - 16:20 #1
Jeg er lidt forvirret.

klasser != instanser

Du kan have 25 instanser af 7 sub klasser.

Instanser af subklasser er automatisk instanser af super klassen.

Du kan naturligvis sende en ref til en instans af klasse X over i alle subklassernes/super klassens constructor og gemme den i en instans variabel.
Avatar billede amews_aj Nybegynder
27. august 2010 - 16:34 #2
klasser != instanser
Nej, hvor mener du da jeg siger det?

Altså jeg mener, jeg kan jo i superklassen lave en statisk variabel, og dermed tilgå denne fra subklasserne. Således vil alle instanser heraf kunne tilgå samme information.
Ellers, kunne jeg i en særskilt klasse (Primary) oprette en privat instansvariabel, og sende en reference med når jeg fra Primary opretter instanser af andre selvstændige klasser. Dermed kan de tilgå fælles information via set/get metoder i Primary klassen. Derved undgås brug af statiske variabler.

Bemærk Primary er selvstændig, og ikke sub/superklasse til nogen af de andre klasser.
Avatar billede arne_v Ekspert
27. august 2010 - 16:39 #3
Det er meget bedre at sende en ref over i constructors.
Avatar billede arne_v Ekspert
27. august 2010 - 16:40 #4
At gemme i en static i super klassen synes jeg kun giver mening, hvis der kun er 1 instans af hver klasse.
Avatar billede amews_aj Nybegynder
27. august 2010 - 16:46 #5
1.Kan du uddybe mere hvorfor det er bedre? Hvad er det dårlige ved at bruge en statisk variabel?
2.Hvorfor skulle det ikke give mening ved flere instanser/objekter af hver klasse?
Avatar billede arne_v Ekspert
27. august 2010 - 17:51 #6
Du har grundliggende en model hvor en instans af en "holder klasse" refererer til M instanser af subklasser til en bestemt klasse.

Saa laengde der kun er 1 instans af "holder klassen", saa vil det at gemme noget static passe med modellen, men faar du mere end en instans af den, saa giver static en anden funktionalitet.
Avatar billede arne_v Ekspert
27. august 2010 - 17:53 #7
Jeg tror saa at det vil vaere paenere at have en separat klasse X til data og have en ref til den i "holder klasse" instansen og sende den med over til instanserne af subklasserne fremfor at sende en ref til instansen af "holder klassen" selv med over.

Det vil bl.a. goere det nemmere at unit teste.
Avatar billede amews_aj Nybegynder
27. august 2010 - 18:06 #8
Er ikke helt med...
Avatar billede arne_v Ekspert
29. august 2010 - 04:12 #9
Prøv og kør disse her to programmer og se hvilken du synes giver bedst mening:


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

public class WrongWay {
    public static void main(String[] args) {
        WWHolder a = new WWHolder("AAA");
        System.out.println("AAA:");
        a.print();
        WWHolder b = new WWHolder("BBB");
        System.out.println("BBB:");
        b.print();
        System.out.println("AAA again:");
        a.print();
    }
}

class WWHolder {
    public static String magic;
    private List<WWP> lst;
    public WWHolder(String s) {
        magic = s;
        lst = new ArrayList<WWP>();
        lst.add(new WWC1());
        lst.add(new WWC2());
    }
    public void print() {
        for(WWP o : lst) {
            o.print();
        }
    }
}

abstract class WWP {
    public abstract void print();
}

class WWC1 extends WWP {
    @Override
    public void print() {
        System.out.println("I am a C1 in " + WWHolder.magic);
    }
}

class WWC2 extends WWP {
    @Override
    public void print() {
        System.out.println("I am a C2 in " + WWHolder.magic);
    }
}



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

public class RightWay {
    public static void main(String[] args) {
        RWHolder a = new RWHolder("AAA");
        System.out.println("AAA:");
        a.print();
        RWHolder b = new RWHolder("BBB");
        System.out.println("BBB:");
        b.print();
        System.out.println("AAA again:");
        a.print();
    }
}

class RWHolder {
    private String magic;
    private List<RWP> lst;
    public RWHolder(String s) {
        magic = s;
        lst = new ArrayList<RWP>();
        lst.add(new RWC1(this));
        lst.add(new RWC2(this));
    }
    public void print() {
        for(RWP o : lst) {
            o.print();
        }
    }
    public String getMagic() {
        return magic;
    }
}

abstract class RWP {
    public abstract void print();
}

class RWC1 extends RWP {
    private RWHolder h;
    public RWC1(RWHolder h) {
        this.h = h;
    }
    @Override
    public void print() {
        System.out.println("I am a C1 in " + h.getMagic());
    }
}

class RWC2 extends RWP {
    private RWHolder h;
    public RWC2(RWHolder h) {
        this.h = h;
    }
    @Override
    public void print() {
        System.out.println("I am a C2 in " + h.getMagic());
    }
}
Avatar billede amews_aj Nybegynder
29. august 2010 - 13:04 #10
Jeg kan godt se din pointe, men i det tilfælde jeg bruger det kan jeg ikke helt se ulempen.

Prøver lige at forklare det lidt mere, inden jeg evt. skriver koden (hvis du vil have den, så sig til).

Altså, vi har en World, som opretter flere instanser af Player.
Player er en subclass af Actor, og indeholder en statisk variabel static int team1Score, team2Score.
Når en Player scorer, opdateres scoren ved dens tilhørende team ved at bruge den statiske varibel i superklassen.
Når spillet er ovre kan scoren aflæses.

Her er jo ikke tale om kald fra World der opdaterer den statiske variabel, og situationer som den du demonstrerede vil jo ikke finde sted.
Er der noget galt i her at anvende en statisk variabel? I så fald hvorfor?

PS: Det er vel korrekt at en statisk variabel der skal bruges i subklassen skal være protected ?
Avatar billede arne_v Ekspert
29. august 2010 - 14:59 #11
Det lyder som en endnu større katastrofe end det eksempel jeg lavede.

Men inden jeg bixer et nyt eksempel som muligvis heller ikke passer med din kode - kan du så ikke lige outline din klasse struktur lidt bedre.

"Player er en subclass af Actor"

og

"Når en Player scorer, opdateres scoren ved dens tilhørende team ved at bruge den statiske varibel i superklassen."

synes jeg virker inkonsistente.
Avatar billede amews_aj Nybegynder
29. august 2010 - 15:18 #12
Ikke lige det bedste kodeeksempel, men prøv at se på dette:

[code]
public class MyTest {
    public static void main(String[] args) {
        MySubClass player1 = new MySubClass(1);
        MySubClass player2 = new MySubClass(1);
        MySubClass player3 = new MySubClass(2);
        MySubClass player4 = new MySubClass(2);

        player1.incrementScore();
        player2.incrementScore();
        player3.incrementScore();

    }
}

class MySuperClass {
    static int team1score = 0;
    static int team2score = 0;

    public MySuperClass() {

    }

    public int getScore(int team) {
        if ( team == 1 ) return team1score;
        else return team2score;
    }
   

}

class MySubClass extends MySuperClass {
    private int team;


    public MySubClass(int team) {
        this.team = team;
    }
   
    public void incrementScore() {
        if ( team == 1 ) team1score++;
        else team2score++;
       
        System.out.println("New score team " + team + ": " + getScore(team));

    }
}
[/code]
Avatar billede amews_aj Nybegynder
29. august 2010 - 15:18 #13
Og så har eksperten erstattet " med &quot; - men det kan du vel let se...
Avatar billede arne_v Ekspert
29. august 2010 - 15:23 #14
Der er to ting galt med den model:

1) Spiller (MySubClass) er ikke en sub klasse til Kamp (MySuperClass).

2) Brugen af static gør at du ikke kan håndtere mere end en kamp korrekt, hvilket er præcis det samme problem som mit eksempel illustrerede.
Avatar billede amews_aj Nybegynder
29. august 2010 - 15:34 #15
1. MySubClass er der subklasse til MySuperClass.
class MySubClass extends MySuperClass {...}

2. Nej korrekt, hvis man oprettede flere kampe på en gang, ville det gå galt. Men så længe det ikke er meningen er der så noget galt? Der er selvfølgelig det galt at man mister muligheden for flere kampe, hvilket vel netop er den stærke side ved at anvende OOP...

3. Egentlig kan man vel også sige at det er forkert at lade superklassen for players holde styr på scoren? I hvert fald ved denne struktor
[code]
MainClass ----- >  Games                    Players
                    /_\                    /_\  /_\
                    |                      |    |
                    |                      |    |
                  Game ------- > PlayerType1    |
                      \------------------------ > PlayerType2
[/code]
Det er jo ikke Players der skal holde styr på scoren i spillet, men vel den enkelte Game-instans? Derfor bør de enkelte playere vel kalde en metode i Game (via reference sendt via constructor), som opdaterer en score gemt i Game?
Ved ikke om det er forståeligt?
Avatar billede amews_aj Nybegynder
29. august 2010 - 15:35 #16
/_\ = nedarver
>  = anvendelse
Avatar billede arne_v Ekspert
29. august 2010 - 15:37 #17
re 1)

Ja - jeg kan godt se at du har brugt extends, men sådan forholder det sig ikke i virkeligheden. Ens objekt model skal modelere virkeligheden.
Avatar billede amews_aj Nybegynder
29. august 2010 - 15:38 #18
Hvad mener du med det?
Avatar billede arne_v Ekspert
29. august 2010 - 15:38 #19
re 2)

Jeg har lidt svært ved at se noget software der på langt sigt kun skal understøtte 1 kamp. Det holder ikke.
Avatar billede amews_aj Nybegynder
29. august 2010 - 15:40 #20
Nej præcis. Nu er dette en eksempel-øvelsesopgave, og derfor er det ikke meningen det skal kunne mere, men ja i den virkelige verden - på længere sigt - vil det jo ikke holde. Skal jo netop sørge for fleksibiliteten..
Avatar billede arne_v Ekspert
29. august 2010 - 15:41 #21
Så vidt jeg kan se skal du have:

Kamp
Hold
Spiller

klasser.

En kamp indeholder to hold.

Et hold indeholder 11 spillere (hvis fodbold andet antal hvis noget andet).

Jeg tror at jeg ville putte score metoden i Kamp klassen med en Spiller som argument.
Avatar billede arne_v Ekspert
29. august 2010 - 15:41 #22
NB: Har du overvejet selvmål ?  (det gør spiller -> resultat lidt mere grumset !)
Avatar billede amews_aj Nybegynder
29. august 2010 - 15:45 #23
(4)

Ja, præcis. Som i ovenstående eksempel vel i Game klassen, da man kan forestille sig flere forskellige subclasses af Games (Forskellige spil).
I Player giver det i hvert fald næppe mening.

(5)
Dog hvis der er tale om spil hvor hver spiller bidrager med en score, så kunne man vel også gemme en lokal score i hver spiller, og hente denne score fra Game klassen, og eksempelvis addere resultatet. Men (4) er vel stadig en væsentlig mere fleksibel løsning?
Avatar billede amews_aj Nybegynder
29. august 2010 - 15:45 #24
(6)
Hvad mener du for øvrigt med "Jeg tror at jeg ville putte score metoden i Kamp klassen med en Spiller som argument. "
Spiller som argument?
Avatar billede arne_v Ekspert
29. august 2010 - 16:29 #25
At jeg tror mere på:

enInstansAfKamp.score(enInstansAfPlayer);

end:

enInstansAfPlayer.score(enInstansAfKamp);
Avatar billede arne_v Ekspert
29. august 2010 - 16:30 #26
Selvom det kun er en øvelse, så tror jeg at du skal undgå de static. Det er kun problemer.
Avatar billede amews_aj Nybegynder
29. august 2010 - 17:49 #27
Ja, så du vil altså:
1. have scoren som en private variabel i Kamp-klassen
2. Give reference til "this" med når Player's oprettes fra Kamp-klassen (altså sende reference til kampklassen med som argument ved kald af constructor)
3. Når score skal opdateres, kalde en mutator metode i Kamp-klassen vha. referencen til Kamp-klassen. ala enInstansAfKamp.score(enInstansAfPlayer);

Har jeg forstået dig rigtigt?
Vil du mene det er den optimale løsning?
Ligeledes metoder som end-game osv. skal vel styres af Kamp-klassen..?

PS: HVIS (hvilket jeg ikke længere har tænkt mig) man bruger statiske variabler til dette, er det så ikke korrekt at en statisk variabel der skal bruges i subklassen skal være protected ? Private er jo for beskyttet, og public er vel for åben.
Avatar billede arne_v Ekspert
01. september 2010 - 02:53 #28
re 1)

yes - to private int

re 2)

jeg vil mene at spillere er tilknyttet et hold og at to hold tilknyttes en kamp

re 3)

ja

re PS)

ja
Avatar billede amews_aj Nybegynder
17. september 2010 - 20:34 #29
Har haft meget travlt i den sidste tid, så helt glemt at svare tilbage her.

Tak for din tid og forklaring.
Smid et svar :)
Avatar billede arne_v Ekspert
17. september 2010 - 20:38 #30
kommer her
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester