Page 2 of 3
In a small application, you can provide the add methods with a javadoc saying, in effect, "Don't call this unless you are the relative performance comparator." As the application
gets larger, and more engineers work on it, this approach becomes riskier. Hardcoding restrictions into the program, instead
of using comments and hoping that everyone reads them, allows the application to detect access bugs automatically.
public class ImmutableIntArray
{
private int[] data;
public ImmutableIntArray (int[] data)
{
this.data = data;
}
int getElementAt (int index)
{
return data[index];
}
}
There is no method that returns the raw data element, because this would defeat the purpose of making the object immutable. Occasionally, however, client code may need to process the contents of data quickly. Although it may take too long to return a copy of the data, working on the raw data element might be fast enough. It would be a reasonable design decision to grant access to data only to those clients who need it, and not to the entire application.
You can create objects whose class names are visible to the entire program, but which can only be constructed by very restricted clients. The objects of these classes can then be used as key objects. Callers are required to pass in these key objects to method calls, and the method being called can check them against a list of legal keys.
Here's a working example of this:
public class Main
{
static public void main (String[] args)
{
try
{
System.out.print ("This should work ...");
ValidExampleCaller.sampleMethod();
System.out.println (" and it did.");
}
catch (InvalidKeyException e1)
{
e1.printStackTrace();
}
try
{
System.out.println ("This should fail ...");
InValidExampleCaller.sampleMethod1();
}
catch (InvalidKeyException e2)
{
e2.printStackTrace();
}
}
}
/**
*
*/
class InvalidKeyException extends java.lang.Exception
{
public InvalidKeyException (String message)
{
super (message);
}
}
class ExampleCallee
{
/**
* This method prints 'Hi!' to standard out, but can only
* be called by the ExampleCaller class.
*
* @param key 'key' is an object restricting access to this
* method. If 'key' is not an instance of
* class ValidExampleCaller.Key, an InvalidKeyException
* is thrown.
*/
public static void sampleMethod (Object key) throws InvalidKeyException
{
if (key.getClass().getName().equals ("ValidExampleCaller$Key") == false)
throw new InvalidKeyException("Can't call sampleMethod() with key " + key);
System.out.println ("Hi!");
}
}
class ValidExampleCaller
{
static private final class Key
{
}
static public void sampleMethod () throws InvalidKeyException
{
ExampleCallee.sampleMethod (new Key());
}
}
class InValidExampleCaller
{
static private final class Key
{
}
static public void sampleMethod1 () throws InvalidKeyException
{
ExampleCallee.sampleMethod (new Key());
}
}
The ExampleCaller class can call the sampleMethod in ExampleCallee successfully, but no other class can.