I have a piece of code where two objects (incoming request
object and a profile
object) are to be checked for matching conditions.
So the first method is as below where I check whether the profile
object will be applied to incoming request
:
public Response apply(Request request) { ..// some logic Profile profile = getProfile(); if( isProfileApplicableOnRequest(profile, request) ) { } return null; } private boolean isProfileApplicableOnRequest(Profile profile, Request request) { List<BigInteger> applicability = profile.getApplicability(); return (applicability != null && applicability.contains(BigInteger.ONE)) || profileMatchesResourceType(profile.getResourceTypes(), request.getResourceType()) || profileMatchesOperation(profile.getOperations(), request.getOperation()) || profileMatchesToParameter(profile.getResourceIDs(), request.getTo()) || profileMatchesReleaseVersion(profile.getReleaseVersions(), request.getReleaseVersionIndicator()) ); }
So here we take values set in request
object and match whether its present in the profile
object. The profile object can have a Lists in which a parameter from request
is checked for.
The functions above in conditional are like:
private boolean profileMatchesResourceType( List<BigInteger> primitiveProfileResourceTypes, BigInteger requestResourceType ){ return (true && primitiveProfileResourceTypes != null && requestResourceType != null && primitiveProfileResourceTypes.contains(requestResourceType) ); } private boolean profileMatchesToParameter( List<String> primitiveProfileResourceIds, String toParameter ){ return (true && primitiveProfileResourceIds != null && toParameter != null && primitiveProfileResourceIds.contains(toParameter) ); } private boolean profileMatchesOperation( List<BigInteger> primitiveProfileOPerations, BigInteger requestOperation ) { return (true && primitiveProfileOPerations != null && requestOperation != null && primitiveProfileOPerations.contains(requestOperation) ); }
Here, since all my match functions are similar I used generics to provide a single method:
private <T> boolean profileMatches( List<T> primitiveProfileAttributes, T oneM2MParam ){ return (true && primitiveProfileAttributes != null && oneM2MParam != null && primitiveProfileAttributes.contains(oneM2MParam) ); }
With this my method looks like:
private boolean isProfileApplicableOnRequest(Profile profile, Request request) { List<BigInteger> applicability = profile.getApplicability(); return (applicability != null && applicability.contains(BigInteger.ONE)) || profileMatches(profile.getResourceTypes(), request.getResourceType()) || profileMatches(profile.getOperations(), request.getOperation()) || profileMatches(profile.getResourceIDs(), request.getTo()) || profileMatches(profile.getReleaseVersions(), request.getReleaseVersionIndicator() ); }
Could I refactor to improve the readability also for this with same profileMatches
being called serially ?
EDIT: Data model
Currently in my implementation, we have a standard XSD/JSON Schema defined by the specifications and I generate Java classes from Schema and keeping those in a jar
file.
So both Request
and Profile
are part of the generated Java classes. So for Request
if we want more member variables we have created a wrapper around it extending the default generated Request
object. So it's treated like a DTO
currently. Profile
is kept as it was generated which holds standard just getter/setters
.
So currently, its mostly suggested in answers to shift logic to Profile
class as it seems like a Domain object. But in CRUD request for Profile
resource, it's passed in the payload over the wire.
So will it be recommended to create a wrapper for Profile
and add domain logic methods to it (keeping transient
variables if newly added variables) ??
EDIT: Functionality
Now, the profiling is full functionality being implemented. Like for various different types of Request
there can be template method to apply Profile
with minor variations inside template.
So in the code above apply()
method is the template method and the isProfileApplicableOnRequest
will have variations like for Subscription request little different logic.
In the above context of data model and functionality will it make sense to shift responsibility on the Profile
object ?
profileMatches
in some kind of loop? If so: loops in Java or C# are a run-time mechanics, generics require the type to be known at compile time. Hence, to make this work in a loop, you could implementprofileMatches
without generics with parameters of typeobject
. Then, you add a run-time check that the passed parameters have the expected types. Finally, callingprofileMatches
in a loop where the input comes from someList<Tuple<T,T>>
should do it. But I think it is debatable if the result will be really more readable.