I'm looking to implement some sort of jQuery
-like object in java-8 which, acting as container, can contain one or more objects.
In Jquery
you can e.g do: $('.bla').addClass('ble');
. It is unknown whether this is applied on one or more objects, yet the method is only one.
I was also very surprised to see that in java-8
you can do CompletableFuture.allOf(CompletableFuture<?>... cfs).join()
.
No matter how many objects you pass, you will get a single CompletableFuture<Void>
and you can call any instance method that will act on all internal objects.
Still, its implementation is definitely too complex for my case.
My base interface
looks like this
public interface Response< T extends DataTransferObject< ? > > {
// instance methods
public boolean isSuccess();
public String getMessage();
public default boolean isUndefined() {
return this.equals(ActionResponse.UNDEF);
}
@SuppressWarnings("unchecked")
public default Response< T > mergeWith(final Response< ? super T > response) {
return Response.allOf(this, response);
}
public default boolean isMultiResponse() {
return this instanceof ActionResponse.ActionMultiResponse;
}
/* -------------------------------------------------------------------------------------------------------------- */
// factory methods
@SuppressWarnings("unchecked")
public static < U extends DataTransferObject< ? > > Response< U > allOf(final Response< ? super U >... responses) {
Objects.requireNonNull(responses);
if (responses.length == 0) return ( Response< U > ) ActionResponse.UNDEF;
return new ActionResponse.ActionMultiResponse< U >(responses);
}
public static < U extends DataTransferObject< ? > > Response< U > from(final boolean success, final String message) {
return new ActionResponse<>(success, message);
}
}
The package-protected class
looks like this (incomplete):
/* Package-protected implementation for the Response< T > type */
class ActionResponse< T extends DataTransferObject< ? > > implements Response< T > {
static final Response< ? extends DataTransferObject< ? > > UNDEF = new ActionResponse<>();
private final boolean success;
private final String message;
private ActionResponse() {
this.success = false;
this.message = null;
}
ActionResponse(final boolean success, final String message) {
this.success = success;
this.message = message;
}
// getters
static final class ActionMultiResponse< T extends DataTransferObject< ? > > extends ActionResponse< T > {
private final String[] messages;
ActionMultiResponse(final boolean success, final String message) {
super(success, message);
this.messages = null;
}
ActionMultiResponse(final Response< ? super T >... responses) {
/* must check if any of the following is already a MultiActionResponse */
// TODO
this.messages = new String[responses.length];
for (int i = 0; i < responses.length; i++) {
this.messages[i] = responses[i].getMessage();
}
}
@Override
public String getMessage() {
if (this.messages == null) return super.getMessage();
return Arrays.toString(this.messages); // dummy string merger
}
}
}
It's important that classes outside of this package
can access only the interface
as I want the implementation details to be hidden. Nobody should care on whether a given instance is a single
or a multi
.
The only way you can build a Response< T >
would be via the factory methods provided or the instance method Response::mergeWith
. E.g:
Response< SpotDTO > response = Response.from(true, "message");
If was wondering if this is indeed a pattern
and if such pattern
has a name? If so, what guidelines should I follow?
What is a better way to implement this concept
?
For instance, I do not like that the ActionResponse
holds a String
type for message
whereas ActionMultiResponse
has String[]
.
Still I do not want to have only one object with a String
array and place if needed only one object inside.
Aucun commentaire:
Enregistrer un commentaire