dispatch class, modularity, initialisation?

Discussion in 'Java' started by bugbear, Sep 3, 2007.

  1. bugbear

    bugbear Guest

    I would like to have a base class
    "Widget", that amongst other things
    has a method getWidgetFor(String name).

    I would like this method to be able to use (e.g.)
    a Widget class static HashMap to look up Widgets.

    Each entry in the Map will be an instance
    of a sub-class of widget; some sub-classes
    may "want" to put more than one entry in the map.

    So - how do I populate the map?

    If I have a static block in each sub-class,
    I have no trivial way of ensuring
    that ALL my subclasses have been referred
    to (thus loading them, and running any static
    code blocks).

    If I have an "init()" method in each sub-class,
    it might be called more than once.

    I welcome advice, tip, examples, opinions etc.

    BugBear
     
    bugbear, Sep 3, 2007
    #1
    1. Advertising

  2. Hi,

    sounds like some kind of Plugin-Mechanism?

    In fact, since you cannot make sure that all subclasses are loaded, you
    also cannot make sure that all static initializers are called (I think
    you have realized that problem already), and of course you cannot make
    sure that the init-methods of all classes are called (same problem)! (Of
    course it would be no problem to secure that they are not called twice
    by using a flag.)

    You say, you need a mapping from "widget name" to "widget class". You do
    not say if you need a list of all available widgets. If you do not need
    such list, a quite easy solution would be to locate the widget classes
    in a certain package and - e.g. if the widget is called "Foo", call the
    class "myWidgetPackage.FooWidget". Then you can easily map the name to a
    class just by calling Class.forName()!

    However, if you need a list of all widgets, you will either have to
    manually list them in a property file or e.g. locate them in a certain
    directory and scan this directory at startup.

    Ciao,
    Ingo




    bugbear wrote:
    > I would like to have a base class
    > "Widget", that amongst other things
    > has a method getWidgetFor(String name).
    >
    > I would like this method to be able to use (e.g.)
    > a Widget class static HashMap to look up Widgets.
    >
    > Each entry in the Map will be an instance
    > of a sub-class of widget; some sub-classes
    > may "want" to put more than one entry in the map.
    >
    > So - how do I populate the map?
    >
    > If I have a static block in each sub-class,
    > I have no trivial way of ensuring
    > that ALL my subclasses have been referred
    > to (thus loading them, and running any static
    > code blocks).
    >
    > If I have an "init()" method in each sub-class,
    > it might be called more than once.
    >
    > I welcome advice, tip, examples, opinions etc.
    >
    > BugBear
     
    Ingo R. Homann, Sep 3, 2007
    #2
    1. Advertising

  3. bugbear

    SadRed Guest

    On Sep 3, 6:44 pm, bugbear <bugbear@trim_papermule.co.uk_trim> wrote:
    > I would like to have a base class
    > "Widget", that amongst other things
    > has a method getWidgetFor(String name).
    >
    > I would like this method to be able to use (e.g.)
    > a Widget class static HashMap to look up Widgets.
    >
    > Each entry in the Map will be an instance
    > of a sub-class of widget; some sub-classes
    > may "want" to put more than one entry in the map.
    >
    > So - how do I populate the map?
    >
    > If I have a static block in each sub-class,
    > I have no trivial way of ensuring
    > that ALL my subclasses have been referred
    > to (thus loading them, and running any static
    > code blocks).
    >
    > If I have an "init()" method in each sub-class,
    > it might be called more than once.
    >
    > I welcome advice, tip, examples, opinions etc.
    >
    > BugBear


    As the value of the Map, use Collection<Entry> instead of a bare Entry
    object.
     
    SadRed, Sep 3, 2007
    #3
  4. bugbear

    bugbear Guest

    SadRed wrote:
    > On Sep 3, 6:44 pm, bugbear <bugbear@trim_papermule.co.uk_trim> wrote:
    >> I would like to have a base class
    >> "Widget", that amongst other things
    >> has a method getWidgetFor(String name).
    >>
    >> I would like this method to be able to use (e.g.)
    >> a Widget class static HashMap to look up Widgets.
    >>
    >> Each entry in the Map will be an instance
    >> of a sub-class of widget; some sub-classes
    >> may "want" to put more than one entry in the map.
    >>
    >> So - how do I populate the map?
    >>
    >> If I have a static block in each sub-class,
    >> I have no trivial way of ensuring
    >> that ALL my subclasses have been referred
    >> to (thus loading them, and running any static
    >> code blocks).
    >>
    >> If I have an "init()" method in each sub-class,
    >> it might be called more than once.
    >>
    >> I welcome advice, tip, examples, opinions etc.
    >>
    >> BugBear

    >
    > As the value of the Map, use Collection<Entry> instead of a bare Entry
    > object.
    >


    I don't understand what part of my problem this helps;
    please expand?

    BugBear
     
    bugbear, Sep 3, 2007
    #4
  5. bugbear

    Lew Guest

    bugbear wrote:
    >>> I would like to have a base class
    >>> "Widget", that amongst other things
    >>> has a method getWidgetFor(String name).
    >>>
    >>> I would like this method to be able to use (e.g.)
    >>> a Widget class static HashMap to look up Widgets.
    >>>
    >>> Each entry in the Map will be an instance
    >>> of a sub-class of widget; some sub-classes
    >>> may "want" to put more than one entry in the map.


    By this, do you mean that a subclass may want to add more than one key, each
    with its own value?

    >>> So - how do I populate the map?


    Have each class register itself with the parent class's registry as part of
    its static initializer.

    public class Sub extends Widget
    {
    static
    {
    synchronized ( Widget.registry )
    {
    registry.put( aKey, someValue );
    registry.put( bKey, otherValue );
    ...
    }
    }
    }

    Obviously all get()s from the registry must be synchronized on the registry, too.

    >>> If I have a static block in each sub-class,
    >>> I have no trivial way of ensuring
    >>> that ALL my subclasses have been referred
    >>> to (thus loading them, and running any static
    >>> code blocks).


    Nope. Just the ones that have initialized.

    One cannot, in general, determine all subclasses from the parent class,
    because new subclasses can be loaded at any moment, including /just/ after
    taking inventory.

    OTOH, each subclass knows of its own existence as it's born, thus can register
    itself as part of its initialization. Thus, while you cannot determine /a
    priori/ that each subclass has been registered, each subclass can guarantee
    that it will not be used until it's registered.

    >>> If I have an "init()" method in each sub-class,
    >>> it might be called more than once.


    Not if you code it right, make it no more visible than package-private, and
    use a factory method instead of a constructor.

    SadRed wrote:
    >> As the value of the Map, use Collection<Entry> instead of a bare Entry
    >> object.


    bugbear wrote:
    > I don't understand what part of my problem this helps;
    > please expand?


    It's a bad idea to keep a collection of Map.Entry as a value, if that's what
    was meant by the advice. It might be a good idea to keep a Collection<V> or
    Collection<? extends V> where V is the type of your values.

    I think SadRed is solving your problem of subclasses registering more than one
    entry, on the reading that you wanted to keep more than one value per key, but
    I'm not sure that's what was meant. I do know that I had to read the original
    post to see if that's what you wanted, or if you wanted to keep several values
    per subclass that have different keys.

    One also wonders how you prevent key collisions between subclasses. Perhaps
    you need a key that is a Pair< Class<? extends Widget>, ? extends KeyType > as
    the key to your map. Thus each subclass entry is keyed by its own class and
    its own key values,

    --
    Lew
     
    Lew, Sep 3, 2007
    #5
  6. bugbear

    bugbear Guest

    Lew wrote:
    > bugbear wrote:
    >>>> I would like to have a base class
    >>>> "Widget", that amongst other things
    >>>> has a method getWidgetFor(String name).
    >>>>
    >>>> I would like this method to be able to use (e.g.)
    >>>> a Widget class static HashMap to look up Widgets.
    >>>>
    >>>> Each entry in the Map will be an instance
    >>>> of a sub-class of widget; some sub-classes
    >>>> may "want" to put more than one entry in the map.

    >
    > By this, do you mean that a subclass may want to add more than one key,
    > each with its own value?
    >
    >>>> So - how do I populate the map?

    >
    > Have each class register itself with the parent class's registry as part
    > of its static initializer.
    >
    > public class Sub extends Widget
    > {
    > static
    > {
    > synchronized ( Widget.registry )
    > {
    > registry.put( aKey, someValue );
    > registry.put( bKey, otherValue );
    > ...
    > }
    > }
    > }
    >
    > Obviously all get()s from the registry must be synchronized on the
    > registry, too.
    >
    >>>> If I have a static block in each sub-class,
    >>>> I have no trivial way of ensuring
    >>>> that ALL my subclasses have been referred
    >>>> to (thus loading them, and running any static
    >>>> code blocks).

    >
    > Nope. Just the ones that have initialized.
    >
    > One cannot, in general, determine all subclasses from the parent class,
    > because new subclasses can be loaded at any moment, including /just/
    > after taking inventory.
    >
    > OTOH, each subclass knows of its own existence as it's born, thus can
    > register itself as part of its initialization. Thus, while you cannot
    > determine /a priori/ that each subclass has been registered, each
    > subclass can guarantee that it will not be used until it's registered.


    Yes. I view this behaviour as more from the "problem ste"
    than from the "solution set"

    >
    >>>> If I have an "init()" method in each sub-class,
    >>>> it might be called more than once.

    >
    > Not if you code it right, make it no more visible than package-private,
    > and use a factory method instead of a constructor.


    Good Thoughts. Thanks you.


    > SadRed wrote:
    >>> As the value of the Map, use Collection<Entry> instead of a bare Entry
    >>> object.

    >
    > bugbear wrote:
    >> I don't understand what part of my problem this helps;
    >> please expand?

    >
    > It's a bad idea to keep a collection of Map.Entry as a value, if that's
    > what was meant by the advice. It might be a good idea to keep a
    > Collection<V> or Collection<? extends V> where V is the type of your
    > values.
    >
    > I think SadRed is solving your problem of subclasses registering more
    > than one entry, on the reading that you wanted to keep more than one
    > value per key, but I'm not sure that's what was meant. I do know that I
    > had to read the original post to see if that's what you wanted, or if
    > you wanted to keep several values per subclass that have different keys.
    >
    > One also wonders how you prevent key collisions between subclasses.
    > Perhaps you need a key that is a Pair< Class<? extends Widget>, ?
    > extends KeyType > as the key to your map. Thus each subclass entry is
    > keyed by its own class and its own key values,


    Ah - well, this goes to the heart of the modularity/context issue
    I'm trying to think about. Clearly (?) the *callers*
    of the registry.get() method SOMEHOW know the names
    they want to use, so "someone" knows "something".

    I guess what this boils down to "who" should know
    the names (and existence) of the various widgets,
    and how should this knowledge should be aggregated in
    (what you nicely called) the registry.

    I'm starting to think that the base class is the correct
    place for this knowledge, and that a static block
    in the base class would be a perfectly "clean" place
    to populate the registry by simple performing code along
    the lines of:

    registry.add("nigel", new WidgetA());
    registry.add("george", new WidgetB("arbitrary"));
    registry.add("henry", new WidgetB("something"));

    BugBear (still coding against 1.4)
     
    bugbear, Sep 3, 2007
    #6
  7. bugbear

    Lew Guest

    bugbear wrote:
    > I'm starting to think that the base class is the correct
    > place for this knowledge, and that a static block
    > in the base class would be a perfectly "clean" place
    > to populate the registry by simple performing code along
    > the lines of:
    >
    > registry.add("nigel", new WidgetA());
    > registry.add("george", new WidgetB("arbitrary"));
    > registry.add("henry", new WidgetB("something"));


    Indeed. If you take that one step more, you will externalize the sub-class
    names to a properties file and let them all have just the default constructor.
    Let each subclass handle its own "arbitrary" or "something" in its own
    initialization (instance preferred to static). Use Class.newInstance() off
    the class object stored as the value, which class object was reflectively
    created upon base class static initialization or static init() method (or even
    reInit()) based on the externalized properties.

    E.g., (untried, uncompiled)

    public class Base
    {
    private static final Map registry = new HashMap();
    // or could use Collections.synchronizedMap()

    private static void initRegistry()
    {
    Properties props = getProperties();
    Map mappings = new HashMap();
    for ( Iterator iter = props.keySet().iterator(); iter.hasNext(); )
    {
    String key = (String) iter.next();
    // here you might have logic to decide whether to use this key
    String name = props.getProperty( key );
    Class clazz = Class.forName( name ); // try...catch omitted for clarity
    mappings.put( key, clazz );
    }
    synchronized ( registry )
    {
    registry.putAll( mappings );
    }
    } // end initRegistry()

    private static Properties getProperties()
    {
    Properties p;
    // read the properties from a resource
    return p;
    }
    }

    --
    Lew
     
    Lew, Sep 3, 2007
    #7
  8. bugbear

    Roedy Green Guest

    On Mon, 03 Sep 2007 10:44:31 +0100, bugbear
    <bugbear@trim_papermule.co.uk_trim> wrote, quoted or indirectly quoted
    someone who said :

    >I would like to have a base class
    >"Widget", that amongst other things
    >has a method getWidgetFor(String name).
    >
    >I would like this method to be able to use (e.g.)
    >a Widget class static HashMap to look up Widgets.
    >
    >Each entry in the Map will be an instance
    >of a sub-class of widget; some sub-classes
    >may "want" to put more than one entry in the map.
    >
    >So - how do I populate the map?
    >
    >If I have a static block in each sub-class,
    >I have no trivial way of ensuring
    >that ALL my subclasses have been referred
    >to (thus loading them, and running any static
    >code blocks).
    >
    >If I have an "init()" method in each sub-class,
    >it might be called more than once.
    >
    >I welcome advice, tip, examples, opinions etc.


    This is what is called a "factory". Look up the factory design
    pattern for some ideas.

    Here are three ways you could handle it:

    1. create constant array:
    PossibleWidgets[] pw = { new Gizmo(), new Thingamabob[]... };

    Then loop through the array getting the string name and adding to a
    HashMap. Lookup by name. Factory hands out the original or a clone
    of the exemplar object.

    2. Look in the HashMap for the string to look up an exemplar object (
    clone or use original as needed) If it is not there, try
    Class.forName, and add it.

    3. Turn the string into an enum with valueOf. Let that enum constant
    either create the object you want or be the object you want.
    --
    Roedy Green Canadian Mind Products
    The Java Glossary
    http://mindprod.com
     
    Roedy Green, Sep 3, 2007
    #8
  9. bugbear

    bugbear Guest

    Lew wrote:
    > bugbear wrote:
    >> I'm starting to think that the base class is the correct
    >> place for this knowledge, and that a static block
    >> in the base class would be a perfectly "clean" place
    >> to populate the registry by simple performing code along
    >> the lines of:
    >>
    >> registry.add("nigel", new WidgetA());
    >> registry.add("george", new WidgetB("arbitrary"));
    >> registry.add("henry", new WidgetB("something"));

    >
    > Indeed. If you take that one step more, you will externalize the
    > sub-class names to a properties file and let them all have just the
    > default constructor. Let each subclass handle its own "arbitrary" or
    > "something" in its own initialization (instance preferred to static).


    That's a lot of typing if I want (say) 30 different
    objects(instances) in the registry, where some
    of them vary in ways that are trivially parameterisable.
    e.g. days of week.

    (I read your code before snipping)

    I guess (as with all code) there's no ONE-size-fits
    all solution, which is why programmers still have a job.

    BugBear
     
    bugbear, Sep 4, 2007
    #9
  10. bugbear

    Lew Guest

    bugbear wrote:
    > Lew wrote:
    >> bugbear wrote:
    >>> I'm starting to think that the base class is the correct
    >>> place for this knowledge, and that a static block
    >>> in the base class would be a perfectly "clean" place
    >>> to populate the registry by simple performing code along
    >>> the lines of:
    >>>
    >>> registry.add("nigel", new WidgetA());
    >>> registry.add("george", new WidgetB("arbitrary"));
    >>> registry.add("henry", new WidgetB("something"));

    >>
    >> Indeed. If you take that one step more, you will externalize the
    >> sub-class names to a properties file and let them all have just the
    >> default constructor. Let each subclass handle its own "arbitrary" or
    >> "something" in its own initialization (instance preferred to static).

    >
    > That's a lot of typing if I want (say) 30 different
    > objects(instances) in the registry, where some
    > of them vary in ways that are trivially parameterisable.
    > e.g. days of week.


    It's the same amount of typing whether you load one object or one hundred.
    That's the beauty of algorithms - one block of code handles arbitrary data set
    sizes.

    I don't understand your objection.

    --
    Lew
     
    Lew, Sep 4, 2007
    #10
  11. bugbear

    bugbear Guest

    Lew wrote:
    >>
    >> That's a lot of typing if I want (say) 30 different
    >> objects(instances) in the registry, where some
    >> of them vary in ways that are trivially parameterisable.
    >> e.g. days of week.

    >
    > It's the same amount of typing whether you load one object or one
    > hundred. That's the beauty of algorithms - one block of code handles
    > arbitrary data set sizes.
    >
    > I don't understand your objection.
    >


    Because in some cases, something may be easily expressed
    by simply parameterising a class; your approach
    (if I've understood) requires a separate class for
    each instance in the registry (since you're using
    Use Class.newInstance() with no parameters
    as the only way to get an instance).

    Creating a class, even using inheritance, just to
    parameterise an instance, is what I'm suggesting
    is a lot of typing.

    BugBear
     
    bugbear, Sep 4, 2007
    #11
  12. bugbear

    Lew Guest

    bugbear wrote:
    > Lew wrote:
    >>>
    >>> That's a lot of typing if I want (say) 30 different
    >>> objects(instances) in the registry, where some
    >>> of them vary in ways that are trivially parameterisable.
    >>> e.g. days of week.

    >>
    >> It's the same amount of typing whether you load one object or one
    >> hundred. That's the beauty of algorithms - one block of code handles
    >> arbitrary data set sizes.
    >>
    >> I don't understand your objection.
    >>

    >
    > Because in some cases, something may be easily expressed
    > by simply parameterising a class; your approach
    > (if I've understood) requires a separate class for
    > each instance in the registry (since you're using
    > Use Class.newInstance() with no parameters
    > as the only way to get an instance).
    >
    > Creating a class, even using inheritance, just to
    > parameterise an instance, is what I'm suggesting
    > is a lot of typing.


    It was not clear from your earlier posts that you were using the same class
    with different parameters to configure each instance.

    The same idea still works, just externalize the parameters. Jeez, doesn't
    anyone extract an apply principles from fragmentary examples any more?

    --
    Lew
     
    Lew, Sep 4, 2007
    #12
  13. bugbear

    bugbear Guest

    Lew wrote:
    >
    > It was not clear from your earlier posts that you were using the same
    > class with different parameters to configure each instance.


    Not everytime, I just like the option:
    The example was:

    registry.add("nigel", new WidgetA());
    registry.add("george", new WidgetB("arbitrary"));
    registry.add("henry", new WidgetB("something"));


    > The same idea still works, just externalize the parameters. Jeez,
    > doesn't anyone extract an apply principles from fragmentary examples any
    > more?


    Jeez - doesn't anyone read the posts they're replying to :)

    BugBear
     
    bugbear, Sep 4, 2007
    #13
  14. bugbear

    Lew Guest

    bugbear wrote:
    > Lew wrote:
    >> It was not clear from your earlier posts that you were using the same
    >> class with different parameters to configure each instance.

    >
    > Not everytime, I just like the option:
    > The example was:
    >
    > registry.add("nigel", new WidgetA());
    > registry.add("george", new WidgetB("arbitrary"));
    > registry.add("henry", new WidgetB("something"));
    >
    >
    >> The same idea still works, just externalize the parameters. Jeez,
    >> doesn't anyone extract an apply principles from fragmentary examples
    >> any more?

    >
    > Jeez - doesn't anyone read the posts they're replying to :)


    You mean like where you said,
    > Each entry in the Map will be an instance
    > of a sub-class of widget; some sub-classes
    > may "want" to put more than one entry in the map.

    ?

    I provided a general pattern, handling the subclass part of your request as
    being the subtler and more directly connected to the pattern. I figured the
    Gentle Reader would extract what they needed from it. I showed the pattern
    for sub-classes; surely you can generalize it to same class, different
    parameters. (Hint: Use a factory instead of a constructor, or don't use the
    default constructor but one that takes the required parameters, or use a builder.)

    --
    Lew
     
    Lew, Sep 4, 2007
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Paul Selibas

    Modularity

    Paul Selibas, Nov 24, 2005, in forum: Java
    Replies:
    3
    Views:
    457
  2. Replies:
    3
    Views:
    471
  3. Tim Clacy
    Replies:
    8
    Views:
    421
    Tim Clacy
    May 30, 2006
  4. Richard Maher
    Replies:
    6
    Views:
    609
    Richard Maher
    Jul 2, 2007
  5. =?iso-8859-1?q?Robin_K=E5veland?=

    Plugins / Modularity

    =?iso-8859-1?q?Robin_K=E5veland?=, Oct 10, 2007, in forum: Python
    Replies:
    3
    Views:
    334
Loading...

Share This Page