【Practical API Design学习笔记】尽量使用package级别访问控制

    package级别访问控制将api的权限设定在只能在包内部使用。有时,我们需要扩展这个功能。比如:我们设计了两个内部包,api不对外开放,那么这两个包中互相访问应该用什么访问控制权限呢?

    看下面的例子:

package com.ting.api;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import com.ting.implement.Accessor;
public final class Item {
  private int value;
  private ChangeListener listener;
  static {
    Accessor.setDefault(new AccessorImpl());
  }
  /** Only friends can create instances. */
  Item() {
  }
  /** Anyone can change value of the item.
  */
  public void setValue(int newValue) {
    value = newValue;
    ChangeListener l = listener;
    if (l != null) {
      l.stateChanged(new ChangeEvent(this));
    }
  }
  /** Anyone can get the value of the item.
  */
  public int getValue() {
    return value;
  }
  /** Only friends can listen to changes.
  */
  void addChangeListener(ChangeListener l) {
    assert listener == null;
    listener = l;
  }
}
package com.ting.implement;

import javax.swing.event.ChangeListener;

import com.ting.api.Item;
public abstract class Accessor {
  private static volatile Accessor DEFAULT;
  public static Accessor getDefault() {
    Accessor a = DEFAULT;
    if (a != null) {
      return a;
    }
    try {
      Class.forName(Item.class.getName(), true,     Item.class.getClassLoader());
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    return DEFAULT;
  }
  public static void setDefault(Accessor accessor) {
    if (DEFAULT != null) {
      throw new IllegalStateException();
    }
    DEFAULT = accessor;
  }
  public Accessor() {
  }
  protected abstract Item newItem();
  protected abstract void addChangeListener(Item item, ChangeListener l);
}
package com.ting.api;

import javax.swing.event.ChangeListener;

import com.ting.implement.Accessor;
final class AccessorImpl extends Accessor {
  protected Item newItem() {
    return new Item();
  }
  protected void addChangeListener(Item item, ChangeListener l) {
    item.addChangeListener(l);
  }
}
Item item = Accessor.getDefault().newItem();
assertNotNull("Some item is really created", item);
Accessor.getDefault().addChangeListener(item, this);

上面的代码可以看出,Item和AccessorImpl都在com.ting.api包中,Accessor在com.ting.implement包中,最后对Item类的调用是在implement包中调用的。这样就实现了在implement包中调用api包中的package权限类。

其中,只有com.ting.api.Item是公开的api,其他三个类都不是公开的。

也就是说,某个开放类的某些方法需要对外部开发者隐藏,但是会被内部调用,我们可以将其设置成package访问控制类型,然后用这种迂回的方式,达到外部不能调用,而内部可以调用的目的。

AccessorImpl类之所以在com.ting.api包中,是因为只有在这个包中才能调用Item的package权限方法等。而AccessorImpl类是package权限,即它对于其他包是不可见的。

总结:Item在类加载时就初始化了AccessorImpl实例,并将其实例传递给Accesstor,Accesstor将AccessorImpl实例以单例的形式保存下来。AccessorImpl实例有个方法会实例化Item,Item的实例化方法是package权限的,所以只能在AccessorImpl对象当前所在的包中实例化。

以上这种是一种设计模式,并不一定要直接继承,使用代理模式也是可以做到的。我们把这种api设计模式称作电话接口,只有打电话的双方才会知道,其他人不知道。

【Practical API Design学习笔记】尽量使用package级别访问控制

你可能感兴趣的:(api)