import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxyForInterfaces {
    public static void main(String[] args) {
        
        Mp3 mp3 = 
new Mp3();
        Mobile mobile = 
new Mobile();
        Mp3 sonyMp3 = 
new SonyMp3();
        Mobile iphone = 
new Iphone();
        
        
        Music music = (Music)Proxy.newProxyInstance(Music.class.getClassLoader(), mp3.getClass().getInterfaces(), 
                
new MusicInvocationHandler(mp3));
        
        music.listenMusic();
        System.out.println(
"--------------------------");
        
        Movie movie = (Movie)Proxy.newProxyInstance(Movie.class.getClassLoader(), 
new Class[]{Movie.class}, 
                
new MovieInvocationHandler(mobile));
        movie.seeMovie();
        System.out.println(
"--------------------------");
        
        
        
        
        
        music = (Music)Proxy.newProxyInstance(Mp3.class.getClassLoader(), Mp3.class.getInterfaces(), 
                
new Mp3InvocationHandler(sonyMp3));
        music.listenMusic();
        System.out.println(
"--------------------------");
        
        music = (Music)Proxy.newProxyInstance(mobile.getClass().getClassLoader(), Mobile.class.getInterfaces(), 
                
new MobileInvocationHandler(iphone));
        music.listenMusic();
        System.out.println(
"--------------------------");
        
        movie = (Movie)Proxy.newProxyInstance(Mobile.class.getClassLoader(), Mobile.class.getInterfaces(),
                
new MobileInvocationHandler(iphone));
        movie.seeMovie();
    }
}
interface Music{
    void listenMusic();
}
interface Movie{
    void seeMovie();
}
class Mp3 implements Music{
    @Override
    
public void listenMusic() {
        System.out.println(
"...now begin music with mp3");
    }
}
class Mobile implements Music,Movie{
    @Override
    
public void seeMovie() {
        System.out.println(
"...now begin movie with mobile");
    }
    @Override
    
public void listenMusic() {
        System.out.println(
"...now begin music with mobile");
    }
}
class SonyMp3 extends Mp3{
    @Override
    
public void listenMusic() {
        System.out.println(
"...now begin music with SonyMp3");
    }
}
class Iphone extends Mobile{
    @Override
    
public void seeMovie() {
        System.out.println(
"...now begin movie(装逼) with Iphone");
    }
    @Override
    
public void listenMusic() {
        System.out.println(
"...now begin music(装逼) with Iphone");
    }
}
class MusicInvocationHandler implements InvocationHandler{
    
    private Music music;
    
public MusicInvocationHandler(Music music){
        
this.music = music;
    }
    @Override
    
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        
        System.out.println(
"before listen music...");
        
        method.invoke(music, args);
        
        System.out.println(
"after listen music...");
        
return null;
    }
}
class MovieInvocationHandler implements InvocationHandler{
    
    private Movie movie;
    
public MovieInvocationHandler(Movie movie){
        
this.movie = movie;
    }
    @Override
    
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        
        System.out.println(
"before see a movie...");
        
        method.invoke(movie, args);
        
        System.out.println(
"after see a movie...");
        
return null;
    }
}
class Mp3InvocationHandler implements InvocationHandler{
    
    private Mp3 mp3;
    
public Mp3InvocationHandler(Mp3 mp3){
        
this.mp3 = mp3;
    }
    @Override
    
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        
        System.out.println(
"before use mp3...");
        
        method.invoke(mp3, args);
        
        System.out.println(
"after use mp3...");
        
return null;
    }
}
class MobileInvocationHandler implements InvocationHandler{
    
    private Mobile mobile;
    
public MobileInvocationHandler(Mobile mobile){
        
this.mobile = mobile;
    }
    @Override
    
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        
        System.out.println(
"before use mobile...");
        
        method.invoke(mobile, args);
        
        System.out.println(
"after use mobile...");
        
return null;
    }
}