[java] change support (weer :P)

Pagina: 1
Acties:
  • 128 views sinds 30-01-2008
  • Reageer

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Ik ben weer eens bezig gegaan met wat changesupport om oa wat makkelijk gui aan te sluiten op modellen door oa berichtgeving mbt veranderingen te vereenvoudigen.

Dit is trouwens nog gebaseerd op de ideeen van de PropertyChangeSupport van Sun, maar ik vind daar een aantal dingen aan vervelend.
1) je kan geen mem leaks overhouden doordat je listeners vergeet te verwijderen. Dit heb ik opgelost (optioneel) met een WeakReference.
2) een foutmelding als support voor een bepaalde property niet bestaat.
3) optimalisatie als er geen change is. Dit zou eventueel ook afgevangen kunnen worden op lager nivo, maar meestal krijg je daar dan onnodig onoverzichtelijke code.

Ik hoor graag jullie commentaar erover (tis nog niet helemaal klaar trouwens).

Ik ben op dit moment ook bezig met een nieuwe List,Map,Tree ChangeSupport waar je ook eenvoudig gui op aan kan sluitens zoals tables en trees.

Naast dit 'ouderwetse' gebeuren ga ik straks ook weer bezig met mijn 'basis' domein objecten waardoor nog veel meer van dit soort zaken op de achtergrond kunnen draaien.


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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
public interface ListenerList<E extends EventListener>{
    
    public void add(E l);
    
    public boolean remove(E l);
    
    public void removeAll();
    
    public List<E> listeners();
}

public final class NormalRefListenerList<E extends EventListener> implements ListenerList<E>{
    private List<E> _listeners = new LinkedList<E>();
    
    public NormalRefListenerList(){}
    
    synchronized public void add(E l){
        if(l == null)
            throw new NullPointerException("l can`t be null");
        
        if(_listeners.contains(l))
            throw new IllegalArgumentException();
        _listeners.add(l);
    }
    
    synchronized public boolean remove(E l){
        if(l == null)
            throw new NullPointerException("l can`t be null");
        
        return _listeners.remove(l);
    }
    
    synchronized public void removeAll(){
        _listeners.clear();
    }
    
    synchronized public List<E> listeners(){
        return new LinkedList(_listeners);
    }
}

public final class WeakRefListenerList<E extends EventListener> implements ListenerList<E>{
    private List<WeakReference<E>> _listenerList = new LinkedList<WeakReference<E>>();
    
    public WeakRefListenerList(){}
    
    synchronized public void add(E l){
        if(l == null)
            throw new NullPointerException("l can`t be null");
        if(contains(l))
            throw new IllegalArgumentException("listener: "+l+" already is listener");
        _listenerList.add(new WeakReference<E>(l));
    }
    
    synchronized public boolean remove(E l){
        if(l == null)
            throw new NullPointerException("l can`t be null");
        return _listenerList.remove(l);
    }
    
    synchronized public void removeAll(){
        _listenerList.clear();
    }
    
    synchronized public List<E> listeners(){
        List<E> result = new LinkedList<E>();
        for(ListIterator<WeakReference<E>> itt = _listenerList.listIterator();itt.hasNext();){
            E ref = itt.next().get();
            if(ref!=null)
                result.add(ref);
            else
                itt.remove();
        }
        
        return result;
    }
    
    private boolean contains(E l){
        assert l!=null:"l can`t be null";
        
        for(Iterator<WeakReference<E>> itt = _listenerList.iterator();itt.hasNext();){
            if(l.equals(itt.next().get()))
               return true;
        }
        return false;
    }
}

public class PropertyChangeSupport<S>{
    private final S _source;
    private final boolean _weakRefs;
    private Map<String,ListenerList<PropertyChangeListener>> _listenerListMap =
        new HashMap<String,ListenerList<PropertyChangeListener>>();
    
    public PropertyChangeSupport(S source, boolean weakRefs){
        if(source == null)
            throw new NullPointerException("source can`t be null");
        _source = source;
        
        _weakRefs = weakRefs;
    }
    
    public PropertyChangeSupport(S source, boolean weakRefs, String[] properties){
        this(source,weakRefs);
        
        if(properties == null)
            throw new NullPointerException("properties can`t be null");
        for(int k=0;k<properties.length;k++)
            addSupport(properties[k]);
    }
    
    
    /**
     * Creates support for property
     *
     * @param    property            a  String
     *
     */
    synchronized public void addSupport(String property){
        if(hasSupport(property))
            throw new IllegalArgumentException("property: "+property+" already is supported");
        
        ListenerList<PropertyChangeListener> list = null;
        if(_weakRefs)
            list = new WeakRefListenerList<PropertyChangeListener>();
        else
            list = new NormalRefListenerList<PropertyChangeListener>();
        
        _listenerListMap.put(property,list);
    }
    
    /**
     * Removes support for property
     *
     * @param    property            a  String
     *
     */
    synchronized public void removeSupport(String property){
        if(!hasSupport(property))
            throw new IllegalArgumentException("property: "+property+" is not supported");
        
        _listenerListMap.remove(property);
    }
    
    
    /**
     * Checks if there is Support for property
     *
     * @param    property            a  String
     *
     * @return   a boolean
     *
     */
    synchronized public boolean hasSupport(String property){
        if(property == null)
            throw new NullPointerException("property can`t be null");
        
        return _listenerListMap.containsKey(property);
    }
    
    
    /**
     * Retuns an array of all Supported Properties
     *
     * @return   a String[]
     *
     */
    synchronized public String[] supports(){
        return (String[])_listenerListMap.keySet().toArray();
    }
    
    synchronized public void addPropertyChangeListener(PropertyChangeListener l){
        throw new UnsupportedOperationException();
    }
    
    synchronized public void addPropetyChangeListener(PropertyChangeListener l, String property){
        get(property).add(l);
    }
    
    synchronized public void removePropertyChangeListener(PropertyChangeListener l){
        throw new UnsupportedOperationException();
    }
    
    synchronized public void removePropertyChangeListener(PropertyChangeListener l, String property){
        get(property).remove(l);
    }
    
    synchronized public void removePropertyChangeListeners(){
        for(Iterator<ListenerList<PropertyChangeListener>> itt = _listenerListMap.values().iterator();itt.hasNext();){
            itt.next().removeAll();
        }
    }
    
    synchronized public void removePropertyChangeListeners(String property){
        get(property).removeAll();
    }
    
    public S getSource(){return _source;}
    
    public void firePropertyChange(String property, int oldValue, int newValue){
        if(oldValue == newValue)
            return;
        fireInternally(property,new Integer(oldValue),new Integer(newValue));
    }
    
    public void firePropertyChange(String property, boolean oldValue, boolean newValue){
        if(oldValue == newValue)
            return;
        fireInternally(property,new Boolean(oldValue),new Boolean(newValue));
    }
    
    public void firePropertyChange(String property, float oldValue, float newValue){
        if(oldValue == newValue)
            return;
        fireInternally(property,new Float(oldValue),new Float(newValue));
    }
    
    public void firePropertyChange(String property, char oldValue, char newValue){
        if(oldValue == newValue)
            return;
        fireInternally(property,new Character(oldValue),new Character(newValue));
    }
        
    public void firePropertyChange(String property, Object oldValue, Object newValue){
        if(oldValue!=null){
            if(oldValue.equals(newValue))
                return;
        }
        fireInternally(property,oldValue,newValue);
    }
    
    private void fireInternally(String property, Object oldValue, Object newValue){
        ListenerList<PropertyChangeListener> l=get(property);
        //send event.
        PropertyChangeEvent pce = new PropertyChangeEvent(_source,property,oldValue,newValue);
        for(Iterator<PropertyChangeListener> itt = l.listeners().iterator();itt.hasNext();){
            itt.next().propertyChange(pce);
        }
    }
    
    private ListenerList<PropertyChangeListener> get(String property){
        if(property == null)
            throw new NullPointerException("property can`t be null");
        
        ListenerList<PropertyChangeListener> result = _listenerListMap.get(property);
        if(result == null)
            throw new IllegalArgumentException("property: "+property+" is not supported");
        return result;
    }
}

[ Voor 5% gewijzigd door Alarmnummer op 13-12-2002 12:31 ]


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Ik heb zelf af en toe nog weleens mijn twijfels bij het werken met dergelijke String identifiers ipv methoden. Je in veel situaties dat deze manier van werken wordt gebruikt om een zeer generieke interface te kunnen maken. Hier zit zeker wat in, maar ik vind dat je hier een hoop bij verliest: een generieke interface definieren zegt maar weinig over de mate waarin twee componenten echt kunnen samenwerken. Het stukje controle wat de compiler doet via de interface definitie gaat volledig verloren. De generieke interface heeft aan de andere kant ook erg weinig nut omdat componenten toch nooit kunnen samenwerken als ze geen kennis hebben van de 'impliciete' interface die er wordt gecreeerd.

Ik zou hiervoor dus graag een beter oplossing zien in de taal zelf: of via losse methoden, of als dat echt niet gaat (gebrek aan functie pointers/delegates/lambda's zal daar de oorzaak van zijn) in ieder geval het gebruik van een enum (eventueel via een type parameter).

Je ziet ditzelfde probleem bijvoorbeeld bij javax.mail en java.sql: de gegevens worden hier doorgegeven met Properties. Dit is dan wel een generieke interface, maar deze heeft dus ook het nadeel dat je absoluut niet kan controleren of de componenten er daadwerkelijk iets mee kunnen.

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


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Ik had zelf ook al even zitten twijfelen aan de String als property. Maar ik wil in 1e instantie een verbetering maken op het object van Sun zonder zelf grote structurele wijzigingen te hoeven doorvoeren in mijn systeem op plaatsen waar ik de PropertyChangeSupport van Sun gebruik.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Daar valt wat voor te zeggen ;) .

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


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
mbravenboer schreef op 13 December 2002 @ 12:51:
Daar valt wat voor te zeggen ;) .
Ik wil meerdere soorten support classes aanbieden. Ik wil een verbeterede versie van PropertyChangeSupport en een paar soortgelijke objecten voor Listen en Map ed.

En verder ben ik maar weer eens begonnen met mijn 'mvc' library

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
public interface Model<C extends Controller>{
    
    public C getController();
    
    public String getDiscription();
}

interface Controller<M extends Model>{
    
    public M getModel();
}


interface PropertyModel<T> extends Model<PropertyController<PropertyModel>>{
    
    public T getValue();
    
    public void setValue(T value) throws VetoException;
}

class VetoException extends RuntimeException{
}

interface PropertyController<M extends Model> extends Controller<M>{
        
    public void addListener(String property, PropertyChangeListener l);
    
    public void removeListener(String property, PropertyChangeListener l);
    
    public void removeAllListeners(String property);
    
    public void removeAllListeners();
    
    public void addVetoListener(String property, VetoableChangeListener v);
    
    public void removeVetoListener(String property, VetoableChangeListener v);
    
    public void removeAllVetoListeners(String property);
    
    public void removeAllVetoListeners();
}

interface ListModel<T> extends Model<ListController<ListModel>>{
    
    public List<T> getList();
}

interface ListController<M extends Model> extends Controller<M>{
    
    public void addListener(ListListener l);
    
    public void removeListener(ListListener l);
    
    public void removeAllListeners();
    
    public void addVetoListener(ListVetoListener l);
    
    public void removeVetoListener(ListVetoListener l);
    
    public void removeAllVetoListeners();
}

interface ListVetoListener extends EventListener{
    
    public void vetoItemAdd(SingleItemListEvent e);
    
    public void vetoItemRemove(SingleItemListEvent e);
    
    public void vetoItemsAdd(MultiItemListEvent e);
    
    public void vetoItemsRemoved(MultiItemListEvent e);
}


interface MapModel<K,V> extends Model<MapController>{

    public Map<K,V> getMap();
}

interface MapController extends Controller<MapModel>{
    
    public void addListener(MapListener l);
    
    public void removeListener(MapListener l);
    
    public void removeAllListeners();
    
    public void addVetoListener(MapVetoListener l);
    
    public void removeVetoListener(MapVetoListener l);
    
    public void removeAllVetoListeners();
}

interface MapListener extends EventListener{
    
    public void itemAdded();
    
    public void itemRemoved();
    
    public void cleared();
}

interface MapVetoListener extends EventListener{
    
    public void itemAdded();
    
    public void itemRemoved();
    
    public void cleared();
}


interface CollectionListener extends EventListener{
    
    public void itemAdded();
    
    public void itemRemoved();
    
    public void cleared();
}

final class ListListenerToCollectionListenerAdapter implements ListListener{
    private final ListListener _colListener;
    
    public ListListenerToCollectionListenerAdapter(CollectionListener colListener){
    }
    
    public void itemAdded(){
    }
    
    public void itemRemoved(){
    }
    
    public void itemsAdded(){
    }
    
    public void itemsRemoved(){
    }
}

final class MapListenerToCollectionListenerAdapter implements MapListener{
    private final ListListener _colListener;
    
    public MapListenerToCollectionListenerAdapter(CollectionListener colListener){
    }
    
    public void itemAdded(){
    }
    
    public void itemRemoved(){
    }
    
    public void cleared(){
    }
}

interface ComposedModel{
}


//vb

class Persoon implements ComposedModel{
    private PropertyModel<String> _voornaamM = new DefaultPropertyModel<String>();
    private ListModel<Persoon> _kinderen = new DefaultListModel<Persoon>();
    
    public Persoon(){
        _voornaamM.getController().addVetoListener(
            new VetoableChangeListener(){
                public void propertyChange(PropertyChangeEvent e){
                    if(e.getNewValue()==null)
                        throw new VetoException("voornaam can`t be null");
                }
            }
        );
    }
    
    public PropertyModel<String> getVoornaamM(){return _voornaamM;}
    
    public ListModel<Persoon> getKinderenM(){return _kinderen;}
}


Het enigste waar ik me zorgen over maak is de snelheid en geheugenverbruik van dit soort structuren.

[ Voor 3% gewijzigd door Alarmnummer op 14-12-2002 12:52 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Intussen is er al weer enorm veel veranderd en het werkt nu een stuk natuurlijker. Verder kwam ik weer tegen die eeuwige en akelige null aan, en voor collectie interfaces zoals List,Map en Tree kwam ik op het idee om daar ook functionaliteit wrappers voor te maken zoals ze er ook zijn voor unmodifiable, synchronized ed. Dus vandaar:

Java:
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
public class NullHatingList<T> implements List<T>{
    private List<T> _internalList;
    
    public NullHatingList(List<T> l){
        if(l == null)throw new NullPointerException("l can`t be null");
        
        //alle elementen moeten nog gecontroleerd worden.
        _internalList = l;
    }
    
    public ListIterator<T> listIterator(int index){
        return new NullHatingListIterator<T>(_internalList.listIterator(index));
    }
    
    public boolean remove(Object item){
        return _internalList.remove(item);
    }
    
    public List<T> subList(int index, int item){
        throw new UnsupportedOperationException();
    }
    
    public int size(){
        return _internalList.size();
    }
    
    public boolean isEmpty(){
        return _internalList.isEmpty();
    }
    
    public boolean contains(Object item){
        return _internalList.contains(item);
    }
    
    public Iterator<T> iterator(){
        return _internalList.iterator();
    }
    
    public Object[] toArray(){
        return _internalList.toArray();
    }
    
    public <T extends Object> T[] toArray(T[] p0){
        return _internalList.toArray(p0);
    }
    
    public boolean add(T item){
        if(item == null) throw new IllegalArgumentException("item can`t be null");
        return _internalList.add(item);
    }
    
    public <X> boolean containsAll(Collection<X> col){
        return _internalList.containsAll(col);
    }
    
    public <T_Sub extends T> boolean addAll(Collection<T_Sub> item){
        return addAll(_internalList.size(),item);
    }
    
    public void add(int index, T item){
        if(item == null)throw new IllegalArgumentException("item can`t be null");
        _internalList.add(index,item);
    }
    
    public <X>boolean removeAll(Collection<X> col){
        return _internalList.removeAll(col);
    }
    
    public T remove(int index){
        return _internalList.remove(index);
    }
    
    public <X> boolean retainAll(Collection<X> col){
        return _internalList.retainAll(col);
    }
    
    public ListIterator<T> listIterator(){
        return new NullHatingListIterator<T>(_internalList.listIterator());
    }
    
    public T get(int index){
        return _internalList.get(index);
    }
    
    public void clear(){
        _internalList.clear();
    }
    
    public T set(int index, T item){
        if(item == null)throw new IllegalArgumentException("item can`t be null");
        return _internalList.set(index,item);
    }
    
    public int indexOf(Object item){
        return _internalList.indexOf(item);
    }
    
    public <T_sub extends T> boolean addAll(int index, Collection<T_sub> col){
        if(col == null)throw new NullPointerException("col can`t be null");
        int k = 0;
        for(Iterator<T_sub> itt = col.iterator();itt.hasNext();){
            if(itt.next() == null){
                throw new IllegalArgumentException("can`t add col, element at index "+k+" is null");
            }
            k++;
        }
        
        return _internalList.addAll(index,col);
    }
    
    public int lastIndexOf(Object item){
        return _internalList.lastIndexOf(item);
    }
    
    public String toString(){
        return _internalList.toString();
    }
    
    public int hashCode(){
        return _internalList.hashCode();
    }
    
    public boolean equals(Object item){
        return _internalList.equals(item);
    }
}


Ik hoop het hele gebeuren voor een groot deel in de kerstvakantie te kunnen afronden en zal ik het op mijn site zetten.

[ Voor 8% gewijzigd door Alarmnummer op 20-12-2002 13:17 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Ik kom trouwens iedere keer weer tot de ontdekking, dat het ontwerpen vanuit interface echt super handig is. Ik loop regelmatig tegen de code van sun aan te schoppen omdat dit gewoon slecht ontworpen is. Ze beginnen meteen vanuit classes dingen op te zetten. Ik weet dat ze op een paar punten later ook hebben gedacht van : STOM! Maar nu zitten we/ze met de gebakken peren. Over het algemeen valt er nog wel een mouw aan te passen, maar het is zo nu en dan wel vrij irritant.

Ik adviseer iedereen dus ook om bijna alles op te zetten vanuit interfaces en daar skeleton (abstracte classes) of default implementaties voor aan te leveren zodat je de vrijheid hebt van interfaces en het gemak van reuse van classes.

En verder is composition een stuk handiger dan enheritance. Door enheritance kan je functionaliteit van een class verbreken en met het oog op de toekomst kan je er eigelijk helemaal niets over zeggen.

Daarnaast zit je met inheritance meteen weer vast aan een bepaalde class bv. NullArrayList, NullVector,NullLinkedList. Als je gebruik maakt van composition, dan heb je er geen last van. Je kan dan zeggen:

new NullHatingList(new Vector()) of new NullHatingList(new LinkedList()).

Oftewel enheritance is vaak overgewardeerd en kan je op veel plekken vervangen door composition. Dit is trouwens alleen weer goed mogelijk als je veel gebruik maakt van interfaces. Dus... interfaces!!!

En tenslotte kan je met een interface extreem duidelijk uitdrukken wat voor functionaliteit iets moet bezitten. Hierdoor kan je niet per ongeluk afhankelijk worden van een methode de niet in de interface vermeld staat.

[ Voor 46% gewijzigd door Alarmnummer op 21-12-2002 11:59 ]


Verwijderd

Meen me te herinneren dat dit advies ook ergens in het begin van het boek "design patterns" van de gang of four werd gegeven.. zoiets als "always design according to interface" en iets als "it's always better to have than to be"... heb het boek uitgeleend dus weet het niet meer precies... Ook vanuit het oogpunt van refactoring is het beter... je altijd nog (vrij) makkelijk dingen aanpassen...

[ Voor 7% gewijzigd door Verwijderd op 21-12-2002 12:13 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Het enigste nadeel aan een interface is dat je er wel aan vast zit. Als je een extra methode aan een interface toevoegd, dan moet hij ook bij alle implementerende classes geimplementeerd worden. Als je werkt vanuit een class dan zal dit probleem minder snel voorkomen. Maar ik vind dit nadeel niet opwegen tegen alle voordelen.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Tja, daarvoor kan je een abstracte default implementatie maken en adviseren om die uit te breiden :) . Als de nieuwe methode in de abstract default implementatie geimplementeerd kan worden is er geen probleem. Als dit niet kan, is er nog steeds een probleem ;) .

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


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
mbravenboer schreef op 21 December 2002 @ 13:54:
Tja, daarvoor kan je een abstracte default implementatie maken en adviseren om die uit te breiden :) .
Mwuahh, is wel een erg magere oplossing :) Ik gebruik op dit moment enorm veel compositions die verder niets anders doen dan berichten forwarden. Ik zou dan niet graag een abstact class daarvoor willen gebruiken.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Mwah, in veel situaties kan je veel abstracte methoden implementeren in termen van nog niet geimplementeerde methoden. Deze methoden voegen dus in feite niets toe, maar zijn toch nodig om makkelijk te kunnen werken met de interface. Deze methoden kan je prima implementeren in de abstracte superklasse en eventueel overriden als je in een subklasse betere performance of ander gedrag wilt. Zo'n hele slechte optie vind ik het dus niet ;) . Je hebt wel gelijk als je het echt over het implementeren van aannames gaat hebben: uiteraard zullen er dan implementaties zijn waarvoor deze aannames niet gelden.

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


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
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
public class NullHaters{

    public static <T> Collection<T> collection(Collection<T> col){
        return new NullHatingCollection<T>(col);
    }
    
    public static <T> List<T> list(List<T> list){
        return new NullHatingList<T>(list);
    }
    
    public static <T> Set<T> set(Set<T> set){
        return new NullHatingSet<T>(set);
    }
    
    public static <T> SortedSet<T> sortedSet(SortedSet<T> sortedSet){
        return new NullHatingSortedSet<T>(sortedSet);
    }
    
    public static <K,V> Map<K,V> map(Map<K,V> map){
        return new NullHatingMap<K,V>(map);
    }
    
    public static <K,V> SortedMap<K,V> sortedMap(SortedMap<K,V> map){
        return new NullHatingSortedMap<K,V>(map);
    }
}


Dit moet worden opgenomen in Collections van Sun ;)

[ Voor 16% gewijzigd door Alarmnummer op 21-12-2002 17:21 ]


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Ik stem voor het ? van Nice ;) .

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


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
*zucht* Als ze dat geparametriseerde polymorfisme probleem nou eens gingen fixen, dan had ik dit niet hoeven maken. Zo lang ze dat niet fixen, kan je er onmogelijk mee werken omdat je te veel beperkingen moet maken in je design.

Maar null problemen kunnen idd veel beter compile time opgelost worden ipv runtime.

Verwijderd

Misschien ben ik heel dom maar hoe kan je null problemen compile time oplossen?

  • bazzs2001
  • Registratie: April 2002
  • Laatst online: 09-04 13:02

bazzs2001

je moet knagen wat lekker is

Verwijderd schreef op 21 december 2002 @ 18:31:
Misschien ben ik heel dom maar hoe kan je null problemen compile time oplossen?
Java:
1
    blaat.add(null);

compiler error: null mag nie

bijvoorbleed (slecht oplossin vind ik)

groeten


Verwijderd

Mmmm denk niet dat Alarmnummer dat bedoelt

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
In java en c is het mogelijk dat de pointer naar een object null is. In Nice is dat niet mogelijk. Als er staat String getVoornaam()
Dan weet je dat je per definitie een String terug krijgt en nooit een null. Maar hoe krijg je dan voor elkaar dat je dan wel een null terug kan sturen? Ze hebben hiervoor gebruik gemaakt van een union type en in nice kan je dat als volgt noteren:
?String getVoornaam()

Als je nu zegt:
String voornaam = getVoornaam()
dan weet je dat je een null of een String terug kan krijgen. Het type van voornaam is dus altijd een niet null waarde, en daar past het antwoord van getVoornaam() niet in => compiletime foutmelding.

[ Voor 6% gewijzigd door Alarmnummer op 21-12-2002 18:53 ]


Verwijderd

ok begrijp nu beter wat je bedoelt.... (btw een simple "klik eens op nice in mijn signature was ook o.k. geweest... maar bedankt voor je uitleg :) ) Als ik het goed begrijp mogen nulls wel maar die moeten expliciet worden aan gegeven en defaulten standaard naar een (null) type van een object (a la het NullObject pattern... of zit ik weer fout?... anders laat maar... ik zal er morgen, als ik wat meer tijd voor heb, er beter naar kijken)

[ Voor 15% gewijzigd door Verwijderd op 21-12-2002 19:12 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Verwijderd schreef op 21 December 2002 @ 19:06:
Als ik het goed begrijp mogen nulls wel maar die expliciet worden aan gegeven en defaulten standaard een een (null) type van een object (a la het NullObject pattern... of zit ik weer fout?)
Ik snap niet helemaal wat je bedoelt.

In Nice wordt er een onderscheid gemaakt tussen een Null type en een Object type. Een union type is een keuze type: of het een, of het andere, bv een String type of een NullType, en dat noteer je dus als ?String

Op die manier kan je dus aangeven wat het type van een bepaald iets moet zijn. En als je ?String in een String veld probeerd te stoppen, dan is dat hetzelfde als een float in een int bv stoppen. Iedere int is een float, maar niet iedere float is een int: het type is te ruim.

Verwijderd

Ok ik begijp het beter... maar dit heeft dus geen impact op de JVM of wel? Indien niet hoe ziet de code eruit als je het door een decompiler (bv jad) heenhaalt? Anyways ... je hoeft hier niet echt op te reageren ... kan morgen het zelf wel even uittesten... maar in iedergeval bedankt voor je uitleg
-----------------------Edit:
sorry iets beter lezen: (van de nice homepage)
The Nice compiler produces java bytecode, which means Nice programs can be executed on virtually any platform, with any Java Virtual Machine.

[ Voor 29% gewijzigd door Verwijderd op 21-12-2002 19:36 ]


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Ik begon me een beetje te ergeren dat ik overal weer wrapper implementaties moest maken, dus ik ben nu voor veel classes (vooral collection framework op dit moment) standaard wrapper implementaties aan het maken die ieder bericht forwarden. Je hoeft dan alleen dmv overloading ervoor te zorgen dat de nieuwe functionaliteit wordt toegevoegd.

  • PhoneTech
  • Registratie: Mei 2000
  • Laatst online: 02-05 20:58
Topic uit den oude doosch, maar zeker wel actueel :)

Ik ben momenteel ook bezig een implemtatie van de propertychangelistener te schrijven

De implementatie van Alarmnummer charmeerd me enigzins, maar er blijven een paar dingen onduidelijk

Stel je hebt de volgende klassen

PersoonList -> Subject
Persoon -> Subject

PersoonListUI -> Observer
PersoonUI -> Observer

de PersoonListUI luistert naar PersoonList
en PersoonUI luistert naar Persoon

De propertychangelistener moet nu gedeeld worden door 4 klassen. IN de implementatie van Alarmnummer wordt de propertychangelistener niet singleton geladen, dus ik neem aan, dat hij per klasse geinstantieerd wordt. Hoe worden de ChangeEvents dan doorgegeven?

Ik heb zelf een implementatie geschreven van het Observer patroon van GoF, maar kom al tegen een aantal situaties waar deze implentatie niet meer voldoet (Een observer die meerdere subject moet monitoren bijvoorbeeld) Ik heb hier een singleton ChangeManager voor gebruikt die als mediator de relaties beheert. Wat ook een probleem is, bij mijn implementatie, is dat de standaard java beans er niet aangehangen kunnen worden.

Nu wil ik dus over naar de enigzins standaard implementatie van Sun.
Is het verstandig om de ChangeManager als singleton te implenteren, zodat iedere observer ook daadwerkelijk changeevents van zelfde instantie ontvangt?

Verwijderd

Alarmnummer schreef op zaterdag 21 december 2002 @ 11:19:
Ik adviseer iedereen dus ook om bijna alles op te zetten vanuit interfaces en daar skeleton (abstracte classes) of default implementaties voor aan te leveren zodat je de vrijheid hebt van interfaces en het gemak van reuse van classes.
Ik zeg spring :*)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
En ik zeg.. zie mijn signature ;)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024
Ik zal je meteen ook maar even een algemene waarschuwing geven. Er zitten een aantal hele grote nadelen aan mijn aanpak.
1) het domain object is verziekt met een bepaald aspect (namelijk de propertychangesupport.. want in 9 van de 10 gevallen wordt hier alleen een gui op aangesloten).
2) domain objecten worden groot en lomp omdat overal zo`n propertychangesupport op is aangesloten. En voor een handje vol objecten valt dat wel mee, maar als je veel objecten hebt dan kan (hoeft neit) het problematisch worden.

Er zijn dus wel een aantal grote problemen aan mijn aanpak :)

Er zijn wel aan aantal alternatieve scenario`s mogelijk
1) het domain object geeft door aan 1 centraal object : ik ben veranderd.. dit is mijn oude en mijn nieuwe waarde. Het probleem met onnodig object verbruik heb je dan wel opgelost maar je domain model is nog steeds een beetje verziekt.
2) je gui gewoon gaan reloaden. Aha.. jij hebt dus iets verandert.. nou doe maar een reload en dan zien we wel waar het schip strandt.

[ Voor 29% gewijzigd door Alarmnummer op 17-12-2004 16:14 ]


  • PhoneTech
  • Registratie: Mei 2000
  • Laatst online: 02-05 20:58
En ik zeg, dat kunnen/mogen we niet gebruiken.

Het gebruik van third party components moet zo laag mogelijk gehouden worden. Ook al wens ik spring te gebruiken, ik kan het gewoon niet doen.
Alarmnummer schreef op vrijdag 17 december 2004 @ 16:10:
Ik zal je meteen ook maar even een algemene waarschuwing geven. Er zitten een aantal hele grote nadelen aan mijn aanpak.
1) het domain object is verziekt met een bepaald aspect (namelijk de propertychangesupport.. want in 9 van de 10 gevallen wordt hier alleen een gui op aangesloten).
2) domain objecten worden groot en lomp omdat overal zo`n propertychangesupport op is aangesloten. En voor een handje vol objecten valt dat wel mee, maar als je veel objecten hebt dan kan (hoeft neit) het problematisch worden.

Er zijn dus wel een aantal grote problemen aan mijn aanpak :)

Er zijn wel aan aantal alternatieve scenario`s mogelijk
1) het domain object geeft door aan 1 centraal object : ik ben veranderd.. dit is mijn oude en mijn nieuwe waarde. Het probleem met onnodig object verbruik heb je dan wel opgelost maar je domain model is nog steeds een beetje verziekt.
2) je gui gewoon gaan reloaden. Aha.. jij hebt dus iets verandert.. nou doe maar een reload en dan zien we wel waar het schip strandt.
1.1. In de listeners worden zo min mogelijk domein objecten geladen. Hoofdzakelijk alleen een simpele klasse met daarin een primary key en een naam.
1.2 zie 1.1 :D

2.1 zie 1.1 :D
2.2 Dat doen we dus ook. zodra een panel een event krijgt dat er een object is veranderd, of nieuw is, dan wordt dat panel opnieuw geladen.

Maar mijn eigenlijk vraag is nog steeds niet beantwoord. Zal ik nu per subject een property change listener initialiseren? of 1 property change listener, waar de subject als key en listeners als value in staan.
Pagina: 1