you are right, the components that just read a collection do just that, read it. they simply ignore the setter method in imodel. no big deal, just because you are given an interface doesnt mean you have to use all the methods in it. thus abstractreadonlymodel.
however, a lot of components manipulate items in the collection. you are right, they can do this without ever needing a setter, but it is very convenient to have a callback that lets you know that the collection has been updated. it is even more convenient to have a callback be part of model itself because in wicket you often factor out conversions and other transformations into the model implementation itself so they are reusable across multiple components. keep in mind models are the glue between components and your domain model, so if any kind of massaging needs to be done for the domain model to work smoothly with the component the model is the perfect place to do it. -igor On Sat, Mar 7, 2009 at 12:25 PM, Johannes Schneider <[email protected]> wrote: > >> i think "misuse" is a pretty bold word considering you are talking to >> people who designed and built imodel, dont you think? :) > > Well, I think you are right. Sorry for that. > I just mean, that it has a bad smell here... > >> >> if we do what you suggest then we would end up with: >> >> interface imodel { object getobject(); } >> interface icollectionmodel extends imodel { object convert(object); } >> interface iwhatevermodel extends imodel { void setobject(object); } >> >> then things that are built on top of imodel now have to be built on >> top of at least two hierarchies (imodel and iwhatevermodel - >> considering icollectionmodel can be a mixin which all implementations >> have to check for which makes it dirty), so we will end up with double >> the classes like loadabledetachablemodel, etc. > > Yes, I think we need at least two interfaces. I don't know whether we > need the icollectionmodel... I think that can be discussed. >> >> where as right now this works perfectly and is quiet elegant: >> >> abstract class collectionconverter<new,old> implements >> imodel<collection<new>> { >> private final imodel<collection<old>> delegate; >> >> public collection<new> getobject() { >> list<new> list=new arraylist<new>(delegate.getobject().size()); >> for (old o:delegate.getobject()) { >> list.add(converttonew(o)); >> } >> return list; >> } >> >> public void setobject(collection<new> object) { >> delegate.getobject().clear(); >> for (new o:object) { >> delegate.getobject().add(converttold(o)); >> } >> } >> >> abstract new converttonew(old o); >> abstract old converttoold(new o); >> } > > Don't know, whether that is really "elegant". It feels more like a > misuse... ;). > I think there is a reason you don't simply take an object for everything > (what might be the most elegant)... > > I really don't understand why IModel must handle the conversion stuff. > That conversion thing could/should be done using some wrapper or > something else. But I don't get all the concepts of Wicket. > I just think that components that just *read* a collection, should just > read the collection... > > But well, as you mentioned correctly, you have designed it, so it is > your choice... > > > Regards, > > Johannes > > >> >> -igor >> >> > >> > Regards, >> > >> > Johannes >> > >> > > >> > > -igor >> > > >> > > On Wed, Mar 4, 2009 at 4:50 AM, Johannes Schneider >> > > <[email protected]> wrote: >> > > > Hi, >> > > > >> > > > the concept of IModel seems to be very obvious. It is simply some kind >> > > > of reference and offers a getter and a setter. >> > > > >> > > > When used with ordinary object, everything works fine. An IModel that >> > > > contains a String can easily be mapped to a TextField. >> > > > The text field calls "getObject" to show the initial value and sets the >> > > > changed string to the model using "setObject" on form commit. >> > > > >> > > > >> > > > Everything becomes a little more complicated when collections are >> > > > affected. The problem is, that it is not obvious what those collections >> > > > represent. >> > > > >> > > > 1) A collection might be read-only (e.g. the possible choices for a >> > > > selection). >> > > > 2) But it also might be necessary to add/remove single elements (e.g. >> > > > privileged users shown within a shuffle list). >> > > > 3) And sometimes the complete collection is changed (can't find an >> > > > example here). >> > > > >> > > > >> > > > IModel only supports the *third* method where the complete collection >> > > > is >> > > > replaced. >> > > > (Don't forget that the reference to the collection changes which will >> > > > lead to several other problems.) >> > > > I strongly recommend the usage of a wrapping class for that case. >> > > > But this case is not very common. Maybe someone finds a good example - >> > > > I >> > > > can't. >> > > > >> > > > >> > > > For the other two cases it does *not* make any sense to call >> > > > IModel#setObject. >> > > > >> > > > >> > > > Summary: Nearly in every case when the IModel contains a collection, >> > > > the >> > > > "setObject" method does not make any sense and must not be called. >> > > > >> > > > >> > > > Conclusion: I think we should have created some sort of IModelProvider >> > > > (contains only the getObject method) and IModel (with both methods). >> > > > Components that just *read* values from the model, accept the read only >> > > > interface now. >> > > > >> > > > For special cases where a magic component adds/removes elements to a >> > > > collection, we need some sort of ICollectionModel that offers "add" and >> > > > "remove" methods (but no setter). >> > > > That interface - of course - will be based upon a collection *without* >> > > > wildcards... >> > > > >> > > > >> > > > >> > > > Regards, >> > > > >> > > > Johannes Schneider >> > > > >> > > > >> > > > >> > > > >> > > > >> > > > >> > > > >> > > > >> > > > >> > > > >> > > > >> > > > >> > > > >> > > > --------------------------------------------------------------------- >> > > > To unsubscribe, e-mail: [email protected] >> > > > For additional commands, e-mail: [email protected] >> > > > >> > > > >> > > >> > > --------------------------------------------------------------------- >> > > To unsubscribe, e-mail: [email protected] >> > > For additional commands, e-mail: [email protected] >> > > >> > >> > >> > --------------------------------------------------------------------- >> > To unsubscribe, e-mail: [email protected] >> > For additional commands, e-mail: [email protected] >> > >> >> --------------------------------------------------------------------- >> To unsubscribe, e-mail: [email protected] >> For additional commands, e-mail: [email protected] >> > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [email protected] > For additional commands, e-mail: [email protected] > > --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
