commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Elijah Zupancic <eli...@zupancic.name>
Subject Re: [chain][v2] clever context - follow-up
Date Mon, 19 Sep 2011 01:18:34 GMT
Hi Simo,

Sorry I was late replying. I've been away at a wedding.

Honestly, I'm not a big fan of Command<K, V, C extends Context<K, V>>. I
agree with you that the it is syntactically clunky. Moreover, I'm not
convinced that the Context design needs to be improved other than the
addition of generics. It is a simple tool that does a simple thing. A
Context allows you to pass state to commands so that a command is always
stateless.

Here are some things that I like about the current context implementation
with Generics.

For example, if we have the following classes:

public class RoomContext extends HashMap<String, Object> implements Context
{
    public static final String HOUSE_NUMBER_KEY = "houseNumber";

    public RoomContext() {}

    public RoomContext(Map<? extends String, ? extends Object> map) {
       super(map);
    }

    public Integer getHouseNumber() {
         return get(HOUSE_NUMBER_KEY);
    }

    public void setHouseNumber(Integer houseNumber) {
         put(HOUSE_NUMBER_KEY,
    }
}

public class KitchenContext extends RoomContext {
    public KitchenContext() {}

    public KitchenContext(Map<? extends String, ? extends Object> map) {
       super(map);
    }

    public static final String STOVE_NAME_KEY = "stoveName";

    public String getStoveName() {
        return get(STOVE_NAME_KEY);
    }

    public void setStoveName(String name) {
        put(STOVE_NAME_KEY, name);
    }

}

public class BedroomContext extends RoomContext {
    public BedroomContext() {}

    public BedroomContext(Map<? extends String, ? extends Object> map) {
       super(map);
    }

    public static final String BED_COLOR_KEY = "bedColor";

    public String getBedColor() {
         return get(BED_COLOR_KEY);
    }

    public void setBedColor(String color)
         // Excuse the American spelling ;)
         put(BED_COLOR_KEY, color);
    }
}

One of the nice things that I can do is this.

KitchenContext kitchen = getInstanceFromSomewhere();
BedroomContext bedroom = new BedroomContext(kitchen);

This would allow me to prepopulate a bedroom object with the relevant house
values and other values from kitchen that I might want to use in subclasses.
That said, sure - you could shoot yourself in the foot with this pattern
(just like any others). Nonetheless, I've used this type of
state inheritance in a number of sequential data processing scenarios and as
long as I only access the getters and setters in the Command class
everything is quite testable and it has a clear to understand contract.
Basically, this is an argument to leave Context inheriting from Map.

Then when the Command is defined as so:

public class RecordHouseNumber implements Command<? extends HouseContext> {
    boolean execute(HouseContext context) throws Exception {
        DataSourceOfSomeKind datasource =
SomeExternalResource.getDataSource();

        datasource.storeHouseNumber(context.getHouseNumber());
    }
}

I don't need to do any casting or any trickery to use beans from a context.
Also, I can just use the context in the class hierarchy that implements the
least amount of functionality needed for a given Command.

Excuse my rambling, but let's return to: Command<K, V, C extends Context<K,
V>>

I believe this is unnecessary because if we leave Command defined without
the K,V generic types like so:

public interface Command<C extends Context> {
    public static final boolean CONTINUE_PROCESSING = false;
    public static final boolean PROCESSING_COMPLETE = true;

    boolean execute(C context) throws Exception;
}

Then we can still access the context's generic methods when we use a command
that implements generics, like so:

public class FooContext extends HashMap<String, Object> implements
Context<String, Object> {

    public <T> T retrieve(String K) {
        return (T)get(K);
    }

}

public class FooCommand implements Command<FooContext> {

    public boolean execute(FooContext context) throws Exception {
        Set<Entry<String,Object>> entrySet =  context.entrySet();

        // do something

        return true;
    }
}

So, as I see it Command<K, V, C extends Context<K, V>> is unneeded.

I will draft a patch that shows, how I would suggest the API to look with
Context<K,V> instead of Context<String, Object>

Ok. I've talked too much. I hope I was able to communicate my ideas clearly.

Thank you,
-Elijah

On Fri, Sep 16, 2011 at 1:40 PM, Simone Tripodi <simonetripodi@apache.org>wrote:

> Hi Elijah,
> I spent some spare time trying to figure out how to improve the
> Context design, I didn't have a lot of success anyway :(
>
>  * dropping the Map inheritance makes not easy maintaining the classes
> in the 'generic' package;
>  * adding generics in the Context to specify K,V types, makes all the
> rest of the notation not so nice (IMHO), take a look as a sample a
> Command<K, V, C extends Context<K, V>> :?
>
> Do you have more ideas?
> Many thanks in advance, all the best!
> Simo
>
> http://people.apache.org/~simonetripodi/
> http://www.99soft.org/
>
>
>
> On Wed, Sep 14, 2011 at 4:12 AM, Elijah Zupancic <elijah@zupancic.name>
> wrote:
> > Hi Everyone,
> >
> > I don't have any votes as I'm not a commiter, but I would still like to
> add
> > in my suggestion.
> >
> > After our previous exchange, I'm of the mind that we should use the
> second
> > option - that is be collection agnostic and work by composition. I may be
> > biased towards defined getters and setters, but I really like to be able
> to
> > use auto-complete, automatic code refactoring tools and static code
> analysis
> > tools. If we used only a Map, then the contract for a context becomes a
> > black box of anything. I like the way it is now where you have to
> implement
> > a Map on your context or extend ContextBase. I may be biased out of habit
> -
> > if so, please convince me (by proxy everyone else).
> >
> > Thanks,
> > -Elijah
> >
> > On Mon, Sep 12, 2011 at 12:04 AM, Simone Tripodi
> > <simonetripodi@apache.org>wrote:
> >
> >> Hi all guys,
> >> after mails and mails of discussions, I don't think there is a general
> >> agreement on how Context API should look alike.
> >> At the end of the discussions I figured out that, briefly resuming, we
> >> have following proposals:
> >>
> >>  * be replaced by Map;
> >>  * be Collection agnostic and work by composition.
> >>
> >> Please add what is missing and correct what is wrong; we need to find
> >> a general agreement before to continue working toward the 2.0 release
> >> :)
> >>
> >> TIA, all the best!!!
> >> Simo
> >>
> >> http://people.apache.org/~simonetripodi/
> >> http://www.99soft.org/
> >>
> >> ---------------------------------------------------------------------
> >> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> >> For additional commands, e-mail: dev-help@commons.apache.org
> >>
> >>
> >
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
> For additional commands, e-mail: dev-help@commons.apache.org
>
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message