Toon posts:

[Java] Read-only access naar een member object

Pagina: 1
Acties:

Verwijderd

Topicstarter
Jaja, mijn eerste Java (:r) topic *D

Ik wil gebruikers van mijn class (andere 'client' programmeurs dus) read-only toegang geven tot een member object van die class.
In C++ zou ik dit doen door een getter method te maken die een reference-to-constant (waarmee het object waarnaar gerefereerd wordt niet aangepast kan worden) returnt, maar aangezien Java dat soort references niet heeft ben ik even 'lost'.

Ik heb op IRC rondgevraagd, maar dat leverde niet veel meer op dan een boel onbegrip en geflame richting C++ ;)

Bruce Eckel's "Thinking in Java" is er ook niet helemaal duidelijk over..

Verder heb ik nog ergens gelezen dat je dan maar een kopie van het object zou moeten maken, maar ik kan me nouwelijk voorstellen dat dat soort toestanden nodig zijn alleen maar om read only toegang te geven.. |:(

Verwijderd

alleen read-methodes?

  • wasigh
  • Registratie: Januari 2001
  • Niet online

wasigh

wasigh.blogspot.com

zorgen dat dat member object alleen getters heeft en geen setters. That should do the trick..

Verwijderd

Topicstarter
Ik zal even een klein voorbeeldje maken om te laten zien wat ik bedoel:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass
{
    int[] arr = new int[10];
}

public class T
{
    public static void main (String[] argv)
    {
        MyClass c = new MyClass();

        // hier wil ik c.arr wel kunnen lezen,
        // maar niet kunnen schrijven
    }
}

  • JapJap
  • Registratie: Maart 2001
  • Laatst online: 07-01 11:02
wasigh:
zorgen dat dat member object alleen getters heeft en geen setters. That should do the trick..
Het object dat je terugkrijgt kan je dan nog wel wijzigen.

Ik denk dat je toch een kopie moet maken... zou zo geen andere oplossing weten. (Ik neem aan dat jet het object zelf wel runtime moet kunnen wijzigen en dat final geen oplossing is.)

Verwijderd

Topicstarter
Op donderdag 15 november 2001 15:35 schreef JapJap het volgende:
Ik denk dat je toch een kopie moet maken... zou zo geen andere oplossing weten.
Damn dat zuigt..
(Ik neem aan dat jet het object zelf wel runtime moet kunnen wijzigen en dat final geen oplossing is.)
Inderdaad, ik wil het object (array in m'n voorbeeld) vanuit de class zelf gewoon zoveel kunnen wijzigen als ik zin in heb.

Verwijderd

Topicstarter
Oja nog even een kleine note: in mijn voorbeeld met de array zou je natuurlijk een int get (int index) kunnen maken, maar dat is natuurlijk geen oplossing als het gewoon om een object gaat.

Verwijderd

Naar mijn weten maakt java altijd een copie. (Pointers? wat is dat);

Klein voorbeeldje:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class test
{
      String bla;

      public test()
      {
            bla = "fiets";
      }

      public String getBla()
      {
            return bla;
      }

      public static void main(String args[])
      {
            test t = new test();
            String newbla = t.getBla();
            System.out.println(newbla);
            newbla = "hallo";
            newbla = t.getBla();
            System.out.println(newbla);
      }
}

fladder@home:~$ java test
fiets
fiets
fladder@home:~$

Verwijderd

Of mag de waarde van de copie ook niet veranderd worden :)

Verwijderd

Topicstarter
Op donderdag 15 november 2001 15:51 schreef fladder wat stuff
Das leuk (als het al allemaal correct is wat jij verkondigt), maareh.. ik snap de link niet helemaal met mijn probleem.. :?

Verwijderd

Hrm

of de oplossing is al 4 keer genoemd (gebruik getters)
of niemand hier die "alleen getters" roept snapt java
of je wilt iets heel ander bereiken dan je hebt uitgelegd

:?

  • JapJap
  • Registratie: Maart 2001
  • Laatst online: 07-01 11:02
fladder:
Naar mijn weten maakt java altijd een copie. (Pointers? wat is dat);
Fout...
code:
1
2
newbla = "hallo";
newbla = t.getBla();

"hallo" is gewoon een nieuwe pointer. Je verandert hier niet de waarde van bla maar laat newbla alleen maar naar een nieuwe string wijzen.

  • JapJap
  • Registratie: Maart 2001
  • Laatst online: 07-01 11:02
fladder:
of niemand hier die "alleen getters" roept snapt java
Nee, jij snapt 'r wat van...

Verwijderd

Op donderdag 15 november 2001 16:00 schreef JapJap het volgende:

[..]

Fout...
code:
1
2
newbla = "hallo";
newbla = t.getBla();

"hallo" is gewoon een nieuwe pointer. Je verandert hier niet de waarde van bla maar laat newbla alleen maar naar een nieuwe string wijzen.
Dat probeer ik dus te vertellen. Ik kan niet de waarde van bla veranderen met alleen getters. Neem me niet kwalijk dat ik hierbij het woord pointer gebruikte.

&newbla->"jij hebt gelijk"

  • JapJap
  • Registratie: Maart 2001
  • Laatst online: 07-01 11:02
code:
1
2
3
  // newbla = "hallo";
  newbla.replace('h', 'b');
  System.out.println(t.getbla());

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 03-09 16:40
const references zoals in C++ zijn niet mogelijk in Java. 't Is balen. Maar de makers van Java geloven in echte inkapseling. Ze vonden dat deze echte inkapseling doorbroken zou worden door references naar member objecten buiten het bezittende object. Getter methodes schrijven voldoet wel aan deze inkapseling.

Wat ook een optie zou zijn is om een wrapper class te maken om het object wat je uit het object haalt. Dit omhullende object staat alleen de get methoden toe. Set zit niet in de interface of is niet toegestaan.

Ik moet even kijken of ik hier een voorbeeldje van heb...

Edit:
Wat ik hierboven dus noemde is het Proxy design pattern:

Even snel een voorbeeldje in elkaar geflanst, ik neem aan dat het zo wel duidelijk zal zijn:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
 * anObject.java
 *
 * Created on 15 november 2001, 19:35
 */

/**
 *
 * @author  Jeroen Leenarts
 * @version 
 */
public class anObject {

    /** Creates new anObject */
    public anObject() {
      veryImportantPrivateData = 666;
    }
    
    private int veryImportantPrivateData;
    
    int getVIPData()
    {
      return veryImportantPrivateData;
    }
    
    void setVIPData(int data)
    {
      veryImportantPrivateData = data;
    }
}


code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * anObjectProxy.java
 *
 * Created on 15 november 2001, 19:38
 */

/**
 *
 * @author  Jeroen Leenarts
 * @version 
 */
public class anObjectProxy {

    /** Creates new anObjectProxy */
    public anObjectProxy(anObject proxiedObject) {
      theProtectedObject = proxiedObject;
    }
    
    anObject theProtectedObject;
    
    int getProxiedData()
    {
      return theProtectedObject.getVIPData();
    }

}


code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * ClassWithDelicateData.java
 *
 * Created on 15 november 2001, 19:41
 */

/**
 *
 * @author  Jeroen Leenarts
 * @version 
 */
public class ClassWithDelicateData {

    /** Creates new ClassWithDelicateData */
    public ClassWithDelicateData() {
      delicateData = new anObject();
    }
    
    anObject delicateData;
    
    anObjectProxy getDelicateData()
    {
      return new anObjectProxy(delicateData);
    }
}

Je moet natuurlijk vanuit je Proxy geen interne data naar buiten beschikbaar stellen. Dus dat betekend primitieve typen naar buiten brengen of references naar kopieën van de interne objecten.

Verwijderd

Op donderdag 15 november 2001 18:36 schreef JapJap het volgende:
code:
1
2
3
  // newbla = "hallo";
  newbla.replace('h', 'b');
  System.out.println(t.getbla());
replace(char oldChar, char newChar)
Returns a new string resulting from replacing all occurrences of oldChar in this string with newChar.

Verwijderd

Topicstarter
Op donderdag 15 november 2001 19:30 schreef The - DDD een uitstekende uitleg
Bedankt voor de uitleg.

En inderdaad erg vervelend dat er een heel design pattern (met kopieën van alle getters in een wrapper class) bij gehaald moet worden voor iets wat zo eenvoudig opgelost zou kunnen worden met een beetje const enzo.

Ik begin me echt af te vragen of ik nog door wil gaan met Java, ook al is het zo populair..

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Op donderdag 15 november 2001 22:29 schreef Sneech het volgende:

[..]

Bedankt voor de uitleg.

En inderdaad erg vervelend dat er een heel design pattern (met kopieën van alle getters in een wrapper class) bij gehaald moet worden voor iets wat zo eenvoudig opgelost zou kunnen worden met een beetje const enzo.

Ik begin me echt af te vragen of ik nog door wil gaan met Java, ook al is het zo populair..
Ik programmeerde vroeger alleen in c en daarvoor in pascal/modula. Maar ik vind java echt een uitstekende taal. Ik denk als je nog een tijdje doorzet dat je dit ook ontdekt (in het begin vond ik het ook heel akelig).

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Sneech: Ik begin me echt af te vragen of ik nog door wil gaan met Java, ook al is het zo populair..
In veel situaties is jouw probleem niet echt een probleem... Voor primitieven is het sowieso geen probleem en die worden toch eigenlijk wel erg vaak gebruikt...

Daarnaast zijn er voor enkele standaard klassen zowel editable als niet editable interfaces. Het gebruik daarvan is uiteraard een uistekende oplossing. Ook als je zelf interfaces schrijft is het erg handig om dit onderscheid te maken.

Verder kan je de standaard Java Collections ook niet-editable maken via Collections.unmodifiable*.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


Verwijderd

Topicstarter
Beetje oude thread, maar ik wil toch nog heel ff verder over die read only wrapper classes met alleen getters.

Stel ik wil read-only toegang voor een class, die weer instances van een andere class bevat, die weer .. etc tot 4 levels diep of zo.
Is er dan geen andere oplossing dan voor al die classes getter-only wrappers te schrijven ?

Hier even een voorbeeld:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// A

    class A // zomaar een classje
    {
        private int x; // leuk intje
            public int getX () { return x; } // getter
            public void setX (int _x) { x = _x; } // setter
    }

    class A_reader // proxyding voor A
    {
        private A a; // eigenlijke object
        A_reader (A _a) { a = _a; } // ctor

        // getters
        public int getX () { return a.getX(); }
    }

// B

    class B // classje met een A object
    {
        private A a = new A ();
            public A getA () { return a; } // getter
            public void setA (A _a) { a = _a; } // setter
    }

    class B_reader // proxyding voor B
    {
        private B b; // eigenlijke object
        B_reader (B _b) { b = _b; } // ctor

        // getters
        public A_reader getA () { return new A_reader(b.getA()); }
    }

// C en C_reader als B en B_reader, etc.

In dit voorbeeld zijn er dus read-only wrappers voor zowel A als B. Als er nu ook nog een C en D waren die respectievelijk B en C objecten zouden bevatten, dan zouden daar ook weer wrappers voor moeten komen.

Is dit echt de normale procedure zo, met onderhoudsgevoelige wrappers overal voor, of ben ik nou helemaal scheef bezig ?

  • Tomatrix
  • Registratie: Juni 1999
  • Laatst online: 27-02-2025
Je zou eventueel mbv. reflectie een algemene 'getter' class kunnen schrijven met maar 1 methode:
code:
1
public Object get (String methodName) throws NoSuchMethodException

Deze klasse neemt een andere klasse die je read-only wil maken als argument voor zijn constructor. In de method get (String) moet je ervoor zorgen dat alleen maar de get methodes aangeroepen kunnen worden (via reflectie).

Met de Proxy klasse in de java.lang.reflect package kan je er voor zorgen dat deze klasse eventueel een apart interface implementeert, zodat je als client niet zoveel hoeft te casten.

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 03-09 16:40
Op maandag 19 november 2001 10:16 schreef Sneech het volgende:
[...]
offtopic:
Deze thread is nog wel redelijk vers hoor. :) En zet de discussie over het onderwerp voort. Geen problemen mee. Dit is een voorbeeldje van ouwe koeien waar je beter een nieuw kalfje voor had kunnen plaatsen: [topic=47568/1/25]


Een andere optie is om de volledige interface een overerving te laten zijn van de wrapper interface. Zo hou je een single point of definition. Als je wil dat een class niet toegankelijk is, gewoon casten naar de wrapper. Wil je er wel weer toegang toe hebben, dan cast je weer terug naar de vollige interface. Probleem hiermee is dat je erg snel problemen krijgt met wat ingewikkeldere class structuren.

Verder is het natuurlijk zo dat wanneer je een Object A met een Object B als member hebt. Je alleen de wrapper om object A hoeft te schrijven. Deze bevat de afgeschermde interface naar Object A en zodoende kun je in de Wrapper om A ook Object B beschermen.

Verwijderd

Topicstarter
Op maandag 19 november 2001 22:28 schreef The - DDD het volgende:
Verder is het natuurlijk zo dat wanneer je een Object A met een Object B als member hebt. Je alleen de wrapper om object A hoeft te schrijven. Deze bevat de afgeschermde interface naar Object A en zodoende kun je in de Wrapper om A ook Object B beschermen.
Klinkt goed, zou je hier een voorbeeldje van kunnen schrijven ?

Hier is de basis:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class B
{
    private int x;
      int getX () { return x; }
      void setX (int _x) { x = _x; }
}

class A
{
    private int y;
      int getY () { return y; }
      void setY (int _y) { y = _y; }
    
    private B b;
      B getB () { return b; }
      void setB (B _b) { b = _b; }
}

En dan moet ik dus read-only access naar x en y hebben. Kan dat met één wrappertje om A ?

  • The - DDD
  • Registratie: Januari 2000
  • Laatst online: 03-09 16:40
Ik ga het niet voor je doen, maar het is doodsimpel.

Gewoon ervoor zorgen dat er van de public interface alleen de get methoden beschikbaar zijn.

Je hebt in je wrapper om B dus een methode die A.get[blaat]() aanroept.
Pagina: 1