代理使得调用方不需要知道实现类是什么,怎么做的,而只需知道如何代理即可。
1)代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
2)代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。如果代码只是为***类提供了代理,在此时还需要对其他类例如:***1类提供代理的话,就需要我们再次添加代理***1的代理类。
我们根据代码来具体看一下静态代理
实现功能:婚庆公司代理你结婚的筹备事宜…
//静态代理
public class StaticProxy {
public static void main(String[] args) {
//代理对象 代理 真实对象
Ming ming = new Ming();
new WeddingCompany(ming).happyMarry();
}
}
//真实对象:小明
class Ming implements Marry{
@Override
public void happyMarry() {
System.out.println("我要结婚了,好hi呦");
}
}
//代理对象:婚庆公司
class WeddingCompany implements Marry{
//婚庆需要有你这个人 , 代理对象需要代理一个真实对象
private Marry ming;
public WeddingCompany(Marry ming){
this.ming = ming;
}
@Override
public void happyMarry() {
before();
this.ming.happyMarry();//你要结婚
after();
}
private void before() {
System.out.println("结婚之前,布置洞房");
}
private void after() {
System.out.println("结婚之后,催你收钱");
}
}
//共同的接口:结婚
interface Marry{
void happyMarry();
}
解释:目标为小明,小明要结婚,那么小明和婚庆公司直接的联系为结婚.因此先创建一个结婚接口,其次小明和婚庆公司都实现这个接口,并重写了happyMarry()方法,婚庆公司也需要一个对象来实施结婚的事宜,因此在婚庆公司类中创建了一个对象ming,实行了静态代理…
因此可以发现,静态代理其实婚庆公司代理了小明结婚的筹备事宜,他们共同实现了Marry这个接口,看到这里有没有觉得静态代理很眼熟呢?没错,就是我们上篇博客讲到的Runnable接口的实现,Runnable接口也是需要自己定义一个实现类,并重写run()方法,之后通过new Thread(实现类对象).start() 来启动线程。原因也是因为Thread和自己定义的实现类都实现了Runnable接口(可以自己查看Thread类的源码,其中有实现Runnable接口),因此Runnable方式其实就是静态代理。
上篇博客链接:JAVA中线程的三种创建方法
上面也提到了静态代理的缺点,就是使用起来会显得代码比较繁琐,但是JDK8中新增了一个Lamda表达式,可以使我们的代码更为的简单。
为什么要使用lambda表达式
Lamda表达式的写法为:
()->{}
其实质属于函数式编程的概念
既然提到了函数式接口编程,我们先来了解一下什么是函数式接口编程:
任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。
public interface Runnable {
public abstract void run();
}
Runnable接口就是一个函数式接口,下面我们从静态内部类到局部内部类,到匿名内部类,再到Lamda表达式说起:
public class Test01 {
//静态内部类
static class Test02 implements Runnable{
@Override
public void run() {
System.out.println("你好呀lambda!");
}
}
public static void main(String[] args) {
Test02 test02 = new Test02();
new Thread(test02).start();
//局部内部类
class Test03 implements Runnable{
@Override
public void run() {
System.out.println("你好呀lambda2!");
}
}
Test03 test03 = new Test03();
new Thread(test03).start();
//匿名内部类, 需要有一个借口或者父类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("你好呀lambda3!");
}
}).start();
//lambda jdk.8新增方式
new Thread(()->{
System.out.println("你好呀lambda4!");
}).start();
}
}
上面写的是Lamda没有传递参数的情况,下面我们写Lambda表达式传递参数的情况,并且仔细讲解:Lamda表达式的各种写法
public class Test03 {
public static void main(String[] args) {
ILove love = new Love();
love.lambda(1);//第一种最为普通的静态代理
//匿名内部类
love = new ILove() {
@Override
public void lambda(int a) {
System.out.println("我开始喜欢lambda了...."+a);
}
};
love.lambda(2);
//lambda表达式
love = (int a)->{
System.out.println("我开始喜欢lambda了...."+a);
};
love.lambda(3);
//简化1: 去掉括号()有一个参数的形式下可以这么做...
love = a->{
System.out.println("我开始喜欢lambda了...."+a);
};
love.lambda(4);
//简化2:之前基础就懂的,在{}内只有一行代码的情况下,是可以省略掉{}的,所以在此处去掉花括号{}
love = a->System.out.println("我开始喜欢lambda了...."+a);
love.lambda(5);
}
}
//函数式接口
interface ILove{
void lambda(int a);
}
class Love implements ILove{
@Override
public void lambda(int a) {
System.out.println("我开始喜欢lambda了...."+a);
}
}
最后再强调一遍:Lamda表达式必须是函数式接口(任何接口,如果只包含唯一一个抽象方法,那么它就是一个函数式接口。)!!!