import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class NullRobot {
    public static void main(String[] args) {
        //1
        Robot r = newNullRobot();
        if(Null.class.isInstance(r)){
//        if(r instanceof Null){ //another way
            System.out.println("[NullRobot]");
        }
        System.out.println(r.name());
        List<Oper> l = r.ops();
        for (Oper oper : l) {
            System.out.println(oper.comm());
        }
        
        //2
        Robot r2 = (Robot) new NullRobotProxyHandler().bind(null);
        if(Null.class.isInstance(r2)){
            System.out.println("[NullRobot]");
        }
        System.out.println(r2.name());
        List<Oper> l2 = r2.ops();
        for (Oper oper : l2) {
            System.out.println(oper.comm());
        }
    }
    
    public static Robot newNullRobot(){
        return (Robot) Proxy.newProxyInstance(
                NullRobot.class.getClassLoader(), //classLoader可以传入哪些?满足什么条件的classLoader可以被用来加载代理类
                new Class[]{Robot.class, Null.class}, 
                new NullRobotProxyHandler());
    }
}

interface Null{}

class NullRobotProxyHandler implements InvocationHandler{

//    Robot proxied = 
    class NRobot implements Robot
    , Null //事实上,可以不继承Null接口,而只要Proxy.newProxyInstance()中的Class[]包含Null.class即可使instanceof判断为true
    {
        private String name = "NoneName";
        @Override
        public String name() {
            // TODO Auto-generated method stub
            return name;
        }
        @Override
        public List<Oper> ops() {
            // TODO Auto-generated method stub
            return Collections.emptyList();
        }
    }
    
    //===another bind way binding real obj with proxy
    public Object bind(Object realObj){
        realObj = new NRobot();
        return (Robot) Proxy.newProxyInstance(
                realObj.getClass().getClassLoader(), 
                realObj.getClass().getInterfaces(), 
                this);
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        return method.invoke(new NRobot(), args);
    }
    
}

interface Oper{
    String comm();
}
interface Robot{
    String name();
    List<Oper> ops();
}
class SnowRobot implements Robot{

    private String name ;
    public SnowRobot(String name){
        this.name = name;
    }
    @Override
    public String name() {
        // TODO Auto-generated method stub
        return name;
    }

    @Override
    public List<Oper> ops() {
        // TODO Auto-generated method stub
        return Arrays.asList(new Oper(){
            @Override
            public String comm() {
                // TODO Auto-generated method stub
                return name +" do1";
            }
        },new Oper(){
            @Override
            public String comm() {
                // TODO Auto-generated method stub
                return name+" do2";
            }
        });
    }
    
}