lundi 29 décembre 2014

Design for request bucket information on client

I'm trying to find the best way to design the client side storage of "buckets". To explain, the server sends down info like:



{
'buckets': {
'some_cool_bucket' : 'val1',
'another_bucket' : 'name'
}
}


Where the values can be



'some_cool_bucket' : 'val1' | 'val2' | 'val3'
'another_bucket' : 'name' | 'cool' | 'other'


basically all these buckets are enums with all the possible values known to both client and server, though there aren't common constraints, like buckets can have any number of possible values (no size limit), and any naming scheme.


I'm struggling against Java to find a design I am happy with. Forget about parsing JSON, blah blah blah, from a design point of view I want to know I can store this data that meets these requirements:



  1. Each bucket needs to be able to store a default value in case server doesn't send one down

  2. bucket.isBucket(...) should be type safe, ie, if we use an enum here, you shouldn't be able to pass in a bucket that doesn't belong without getting an error.

  3. Easy, simple access. Buckets.some_cool_bucket.is(val1) would be ideal.

  4. Minimal boiler plate in adding a new bucket

  5. Non confusing design


Ignoring these requirements, we could implement this as follows:



enum Bucket {
some_cool_bucket('val1'),
another_bucket('name');

Bucket(String default) {
[...]
}

// Assume this retrieves the stored value sent down from the server.
String getVal() {
[...]
}

boolean is(String val) {
return getVal().equals(val);
}
}


With usage Bucket.some_cool_bucket.is('val1'). Naturally, we would want to extend this by changing the type signature of is() to accept some val enum defined by some_cool_bucket. Since the values a bucket can take are not uniform, we'd have to define this inside the some_cool_bucket enum. But you can't have enums inside enums in Java.


Ok, reset. Let's try this again:



public abstract class BaseBucket<E extends Enum<E>> {

private final Class<E> mClazz;
private final E mDefaultBucket;

public BaseBucket(Class<E> clazz, E defaultBucket) {
mClazz = clazz;
mDefaultBucket = defaultBucket;
}

// Assume this retrieves the stored value sent down from the server, uses
// getName() to match with the data.
protected E getVal() {
[...]
}

protected abstract String getName();

public boolean is(E test) {
return getVal() == test;
}
}

public class SomeCoolBucket extends BaseBucket<Val> {
public SomeCoolBucket() {
super(Val.class, Val.val1);
}

@Override
public String getName() {
return "some_cool_bucket";
}

public enum Val {
val1, val2, val3;
}
}

public Buckets {
public static final SomeCoolBucket some_cool_bucket = new SomeCoolBucket();
}


Ok, this works! Great. It meets all the functional requirements, but it's cumbersome and I hate having to create a new class for each bucket. I find it hard to justify all of the code, though I believe the requirements are sound.


Does anyone have a better solution for this?


Aucun commentaire:

Enregistrer un commentaire