Reputation: 805
I have a service class that contains several methods, as shown below. The specifics of what this class is doing is described at the end of this post.
public class Service{
public Foo m_a( /* args_a */ ){ ... }
public Bar m_b( /* args_b */ ){ ... }
// and so on
}
All public methods in that service have one thing in common : they call an init()
method before doing anything else. So, my service rather looks like this :
public class Service{
private int attr;
private void init(int val){
this.attr = val;
}
public Foo m_a(int val_a, ...){
init(val_a);
// time for business A
}
public Bar m_b(int val_b, ...){
init(val_b);
// time for business B
}
// and so on
}
Since other methods may be added to Service
in the future, I think the design above is quite poor. The guy that implements a new method for this class might not follow the rule of calling init(val_x)
first, and it may lead to errors.
To ensure that init()
is always called, I can create some proxy method that does the job systematically :
public class Service{
// Init method
private int attr;
private void init(int val){
this.attr = val;
}
/*
* The only public method in the service is a proxy,
* that always calls init() before calling the actual requested method
*/
public Object invoke(String method, int val, Map<String,Object> args){
init(val);
switch(method){
case "m_a":
return m_a(args.get("name"),...);
case "m_b":
return m_b(args.get("myArg"),...);
default: // launch some exception
}
}
private Foo m_a( /* args_a */ ){ ... }
private Bar m_b( /* args_b */ ){ ... }
// and so on
}
I think it's a much nicer approach, and a developper that has to maintain the code will have no difficulty to understand what's going on.
However I see a large drawback in this solution : the usability for the user !
Map
object before calling the invoke
method, instead of entering the arguments directly in the method signatureinvoke
is Object
, which is tremendously ambiguous and requires the user to apply casting at every call of invoke
Do you guys have any clever idea on how to remove those problems, and still keep this proxy idea ?
Service
classWhat I'm actually doing is implementing a REST API. The goal of this API is to access specific resources stored in a database. For instance :
GET http://fortheking.com/topic/3
This HTTP requests will be linked to a service method that fetches a specific topic, given its ID.
In practice, "topic" is the name of the resource to be accessed. It is the entry point of each and every method of my Service
class, and so there is some common code to be applied before actually starting the intended logic of the method. I have put such code in init()
.
Upvotes: 1
Views: 269
Reputation: 98
Fundamentally, you want to use a Java Proxy with an ImplementationHandler. This blog is a bit dated, but explains the basic concepts: http://www.ibm.com/developerworks/library/j-jtp08305/ - the "Dynamic proxies as Decorators" section is probably most relevant for you. The idea is that you would return a "Service" instance to your callers that is really a proxy object. In that proxies InvocationHandler, you could call the init() method and then execute the main method. If you have existing methods that also call init(), you either need to make sure that init() is idempotent, or change the code to not call it twice.
One limitation of this approach is that you can only create a proxy for an Interface, not for a Class. (Unless this limitation has been lifted in some recent version of Java that I haven't looked at yet.) I recognize your sample code above is simplified, but you do not show any interfaces, so this may be something that you need to introduce first. Most importantly, the callers of your service must use the Interface and not the Service class directly.
Upvotes: 1