I have methods set to public because they must be called by an exterior class, but I only ever want them called by one or two methods. Being called by other methods could create bugs in my program. So, in order to prevent me from accidentally programming around my own methods, I have been doing stuff like this within the methods of which I want to restrict callers:
if(trace.length<2){
throw new Exception("Class should not call its own function.");
}else if(trace[1].getClassName()!=desiredClassName || trace[1].getMethodName()!=desiredMethodName){
throw new Exception(trace[1].getClassName()+"\" is invalid function caller. Should only be called by "+desiredClassName+"->"+desiredMethodName+".");
}
Is there something else I开发者_StackOverflow中文版 should be doing, or should I just not forget how my program works?
You should be using visibility to restrict calling - making a method public (or for that matter, javadocing it) is not going to work unless you have dicipline (and you control the callers too). From your description, you are neither.
What you can do is make the class package private, and put it in the same package as the two callers of that class. As long as you have a proper package structure, this can work. E.g.: Your class that should only be called by A and B:
package thepackage.of.a.and.b;
//imports here
class CallableByAB {
public void methodA(){}
public void methodB(){}
}
A:
package thepackage.of.a.and.b;
public class A {
/*...other code here */
new CallableByAB().methodA();
/*...other code here */
}
B:
package thepackage.of.a.and.b;
public class B {
/*...other code here */
new CallableByAB().methodB();
/*...other code here */
}
other classes cannot call new CallableByAB()
or import it. hence, safety.
This seems like a very brittle solution to a problem you should not need to solve.
In this particular case you may not suffer too greatly in future maintenance, just a couple of methods with these kind of special guards. But imagine trying to apply such logic to many methods across a large code base - it's just not a tenable thing to do. Even in your case you are effectivley writing code that cannot be reused in other contexts.
The fact that you need to do this surely reflects some kind of mis-design.
I infer that you have some kind of stateful interface whose state gets fouled up if called unexpectedly. Ideally I would want to make the interface more robust, but if that just cannot be done: If there are particular methods that should use this interface can you move those methods to a specific class - maybe an inner class of the current objtec you have - and have a handle visible only in this class?
private Class TheLegalCaller {
private RestrictedCallee myCallee = new RestricatedCallee() ; // or other creation
public void doOneThing() { myCallee.doOne(); }
public void doOtherThing() } myCallee.doOther(); }
}
Now the downside with this is that it only pushes the problem up a level, if you randomly use TheLegalCaller in the wrong places then I guess you still have an issue. But maybe by making the restriction very visible it aids your memory?
Try using access rules.
http://groups.google.com/group/google-web-toolkit/browse_thread/thread/90c424dc44db523e
I found a very simple way to do that, but requires some coding methodology:
class AllowedCaller {
private Object key;
public boolean getKey(){
return key;
}
public void allowedCallingMethod(RestrictedAccessClass rac){
this.key = rac;
rac.restrictedMethod();
this.key = null;
}
}
class RestrictedAccessClass{
public void restrictedMethod(){
if(allowedCallerInstance.getKey() != this){
throw new NullPointerException("forbidden!");
}
// do restricted stuff
}
}
I think it could be improved to prevent multithread simultaneous access to restrictedMethod().
Also, the key could be on another class other than AllowedCaller (so RestrictedAccessClass would not need to know about AllowedClass), and such control could be centralized, so instead of a single key, it could be an ArrayList with several object keys allowed at the same time.
精彩评论