罗明的博客
... ...
讨论Eclipse, Java, Linux, Google产品
              
Source: http://openide.netbeans.org/tutorial/api-design.html#design.less.friend
Allow access only from a friend code
Another useful technique to not expose too much in API is to give access to certain functionality (e. g. ability to instantiate a class or to call a certain method) just to a friend code.

Java by default restricts the friends of a class to those classes that are in the same package. If there is a functionality that you want share just among classes in the same package, use package-private modifier in definition of a constructor, a field or a method and then it will remain accessible only to friends.

Sometimes however it is more useful to extend the set of friends to a wider range of classes - for example one wants to define a pure API package and put the implementation into separate one. In such cases following trick can be found useful. Imagine there is a class item:

public final class api.Item {
    /** Friend only constructor */
    Item(int value) {
        this.value = value;
    }

    /** API method(s) */
    public int getValue() {
        return value;
    }
        
    /** Friend only method */
    final void addListener(Listener l) {
        // some impl
    }
}
that is part of the API, but cannot be instanitated nor listened on outside of the friend classes (but these classes are not only in api package). Then one can define an Accessor in the non-API package:
public abstract class impl.Accessor {
    public static Accessor DEFAULT;

    static {
        // invokes static initializer of Item.class
        // that will assign value to the DEFAULT field above
        Class c = api.Item.class;
        try {
            Class.forName(c.getName(), true, c.getClassLoader());
        } catch (ClassNotFoundException ex) {
            assert false : ex;
        }
        assert DEFAULT != null : "The DEFAULT field must be initialized";
    }

    /** Accessor to constructor */
    public abstract Item newItem(int value);
    /** Accessor to listener */
    public abstract void addListener(Item item, Listener l);
}
with abstract methods to access all friend functionality of the Item class and with a static field to get the accessor's instance. The main trick is to implement the Accessor by a (non-public) class in the api package:
final class api.AccessorImpl extends impl.Accessor {
    public Item newItem(int value) {
        return new Item(value);
    }
    public void addListener(Item item, Listener l) {
        return item.addListener(l);
    }
}
and register it as the default instance first time somebody touches api.Item by adding a static initializer to the Item class:
public final class Item {
    static {
        impl.Accessor.DEFAULT = new api.AccessorImpl();
    }

    // the rest of the Item class as shown above
}
Then the friend code can use the accessor to invoke the hidden functionality from any package:
api.Item item = impl.Accessor.DEFAULT.newItem(10);
impl.Accessor.DEFAULT.addListener(item, this);


版权所有 罗明
posted on 2006-01-05 21:01 罗明 阅读(384) 评论(0)  编辑  收藏 所属分类: Java

只有注册用户登录后才能发表评论。


网站导航: