//服务接口
public interface Service {
public void move();
}
public class Train implements Service{
public void move(){
System.out.println(this.getClass().getName().substring(this.getClass().getName().lastIndexOf(".")+1)+" can run.");
}
}
public class Plane implements Service {
public void move(){
System.out.println(this.getClass().getName().substring(this.getClass().getName().lastIndexOf(".")+1)+" can fly.");
}
}
//服务提供者接口
public interface Provider {
Service newService();
}
public class TrainProvider implements Provider{
@Override
public Service newService() {
return new Train();
}
}
public class PlaneProvider implements Provider {
@Override
public Service newService() {
return new Plane();
}
}
public class Services {
private Services(){} //私有化构造函数,禁止创建Services的实例
//用Map存储service及其对应的名称
private static final Map<String,Provider> providers=
new ConcurrentHashMap<String,Provider>();
public static final String DEFALUT_PROVIDER ="<def>";
//注册provider的API
public static void registerDefaultProvider(Provider p){
registerProvider(DEFALUT_PROVIDER,p);
}
public static void registerProvider(String name,Provider p){
providers.put(name, p);
}
//获取service的API
public static Service newInstance(){
return newInstance(DEFALUT_PROVIDER);
}
public static Service newInstance(String name){
Provider p=providers.get(name);
if(p==null)
throw new IllegalArgumentException("No provider registered with name: "+name);
return p.newService();
}
}
//客户程序
public class Client {
public static void main(String[] args){
//创建服务提供者
Provider p1=new TrainProvider();
Provider p2=new PlaneProvider();
//注册服务
Services.registerProvider("train", p1);
Services.registerProvider("plane", p2);
//获取服务
Service s1=Services.newInstance("train");
Service s2=Services.newInstance("plane");
//使用服务
s1.move();
s2.move();
}
}
服务提供者接口(Service Provider Interface)可以不要,这个时候可以按照类名来注册服务,并且通过反射的方法对服务进行实例化。
public class Services {
private Services(){}
private static final Set<String> services=
new LinkedHashSet<String>();
public static final String DEFAULT_SERVICE_NAME="<def>";
//注册服务的API
public static void registerDefaultService(){
registerService(DEFAULT_SERVICE_NAME);
}
public static void registerService(String name){
services.add(name);
}
//获取服务的API
public static Service newInstance(){
return newInstance(DEFAULT_SERVICE_NAME);
}
public static Service newInstance(String name){
if(!services.contains(name))
throw new IllegalArgumentException("No provider registered with name: "+name);
Service s=null;
try{
String package_path=Services.class.getName().substring(0,Services.class.getName().lastIndexOf(".")+1);
s=(Service)Class.forName(package_path+name).newInstance();
}catch(ClassNotFoundException e1){
System.err.println("class not found.");
System.exit(1);
}catch(IllegalAccessException e2){
System.err.println("class not accessible.");
System.exit(1);
}catch(InstantiationException e3){
System.err.println("class not instantiable.");
System.exit(1);
}
return s;
}
}
public class Client {
public static void main(String[] args){
//注册服务
Services.registerService("Train");
Services.registerService("Plane");
//获取服务
Service s1=Services.newInstance("Train");
Service s2=Services.newInstance("Plane");
//使用服务
s1.move();
s2.move();
}
}
使用反射有3个缺点:
- 丧失了编译时类型检查的好处。上例中会产生3个运行时错误,如果不使用反射,这3个错误都会成不编译时错误。
- 代码冗长。由于要catch运行时错误,代码变得冗长。
- 性能损失。反射方法比普通方法的调用慢许多。
System.exit很少使用,它会终止整个VM,但是它对于命令行有效性的非法终止是很合适的。