静态代理模式:
什么是代理模式? 举个例子吧,就比如超市的产品,超市的产品是由厂家生产,但是我们用户一般不会直接找厂家,二十通过超市去购买产品;
代理模式也是如此:-
这个是常见代理模式常见的 UML 示意图:
值得注意的是代理模式的几点:
- 用户只关心接口功能,而不在乎谁提供了功能。上图中接口是 Subject。就像用户不会关心出售的是谁只会关心产品怎样.
- 接口真正实现者是上图的 RealSubject,但是它不与用户直接接触,而是通过代理。 就像是产品是厂家生产的,而用户是通过超市去购买产品不予用户进行直接接触;
- 代理就是上图中的 Proxy,由于它实现了 Subject 接口,所以它能够直接与用户接触。就像是用户购买东西都选择去超市进行购买,而不会选择厂家购买一样;
- 用户调用 Proxy 的时候,Proxy 内部调用了 RealSubject。所以,Proxy 是中介者,它可以增强 RealSubject 操作。用户买了产品,实际上是厂家产出的,而超市是作为中间商,它可以是不是做做活动,打打广告来推销产品;
不多说先上代码 (聚合方式):
我以下讲的方式为聚合,这种方式比较灵活,更推荐使用这种方式,这种方式,先产生一个汽车的代理类ProductProxy,让它也去实现Product接口,再将ProductImpl类以成员变量的方式引入,通过构造器赋值,此时就可以在实现的接口方法中调用ProductImpl方法和插入我们要执行的逻辑。
1.先定义一个接口(Product)作为约束
package demo;
/**
* 定义一个产品接口
* 这个产品有自己的规格参数作
*
* 也就是把这个接口作为一个约束 约定
*@Author ange
*@Date 2020/7/8 14:20
**/
public interface Product {
/**
* 产品名称
* @return
*/
String getName();
/**
* 产品用途
*/
void getDo();
}
2.定义一个具体的委托类(ProductImpl),它就是即将要被代理的类:
package demo;
import lombok.extern.slf4j.Slf4j;
/**
* 这是产品的具体实现类,也可以看为工厂产出的具体对象
*
*@Author ange
*@Date 2020/7/8 14:25
**/
@Slf4j
public class ProductImpl implements Product {
@Override
public String getName() {
return "我是一个产品,我是一个电视!";
}
@Override
public void getDo() {
log.info("我是电视!我可以播放奥特曼!");
}
}
3.定义一个代理类(ProductProxy),去代理委托类
package demo;
import lombok.extern.slf4j.Slf4j;
/**
* 代理类 可以看成是超市,首先超市要去工厂里进货,拿到货以后进行推销,也就是拓展
*
*@Author ange
*@Date 2020/7/8 14:33
**/
@Slf4j
public class ProductProxy implements Product {
private Product product;
public ProductProxy(Product product){
this.product = product;
}
@Override
public String getName() {
//我们可以在推销过程中可以进行推销,也就是扩展
String name = product.getName();
name += "我是星星品牌的大电视机,全球销量第一!世界最强";
return name;
}
@Override
public void getDo() {
product.getDo();
log.info("我还可以看天气预报!");
log.info("我还可以看新闻!");
}
}
看一下效果:
package demo;
import lombok.extern.slf4j.Slf4j;
/**
*@Author ange
*@Date 2020/7/8 14:45
**/
@Slf4j
public class Demo {
public static void main(String[] args) {
Product product = new ProductImpl();
Product proxy = new ProductProxy(product);
log.info(proxy.getName());
proxy.getDo();
}
}
打印结果:
14:46:38.863 [main] INFO demo.Demo - 我是一个产品,我是一个电视!我是星星品牌的大电视机,全球销量第一!世界最强
14:46:38.888 [main] INFO demo.ProductImpl - 我是电视!我可以播放奥特曼!
14:46:38.888 [main] INFO demo.ProductProxy - 我还可以看天气预报!
14:46:38.888 [main] INFO demo.ProductProxy - 我还可以看新闻!
可以看到他的执行过程,首先工厂产出了一个产品也就是 Product product = new ProductImpl(); 接着把这个产品给予超市让它代理出售 Product proxy = new ProductProxy(product); 超市为了提升自己的销量,觉得现在的产品的参数太过平平没有吸引力,所以做了一些广告包装:
@Override
public String getName() {
//我们可以在推销过程中可以进行推销,也就是扩展
String name = product.getName();
name += "我是星星品牌的大电视机,全球销量第一!世界最强";
return name;
}
@Override
public void getDo() {
product.getDo();
log.info("我还可以看天气预报!");
log.info("我还可以看新闻!");
}
静态代理的另一种实现方式 (继承) :
不推荐使用这个使用方式,应为这种方式不够灵活,代码比较臃肿,它只是直接以继承的方式去继承ProductImpl,然后调用父类的方法和参数进行拓展
1.先定义一个接口(Product)作为约束
package demo;
/**
* 定义一个产品接口
* 这个产品有自己的规格参数作
*
* 也就是把这个接口作为一个约束 约定
*@Author ange
*@Date 2020/7/8 14:20
**/
public interface Product {
/**
* 产品名称
* @return
*/
String getName();
/**
* 产品用途
*/
void getDo();
}
2.定义一个具体的委托类(ProductImpl),它就是即将要被代理的类:
package demo;
import lombok.extern.slf4j.Slf4j;
/**
* 这是产品的具体实现类,也可以看为工厂产出的具体对象
*
*@Author ange
*@Date 2020/7/8 14:25
**/
@Slf4j
public class ProductImpl implements Product {
@Override
public String getName() {
return "我是一个产品,我是一个电视!";
}
@Override
public void getDo() {
log.info("我是电视!我可以播放奥特曼!");
}
}
3.定义代理类继承ProductImpl
package demo;
import lombok.extern.slf4j.Slf4j;
/**
* 继承的方式 代理产品
*@Author ange
*@Date 2020/7/8 15:23
**/
@Slf4j
public class ProductProxyExtend extends ProductImpl {
public String getName(){
//我们可以在推销过程中可以进行推销,也就是扩展
String name = super.getName();
name += "我是星星品牌的大电视机,全球销量第一!世界最强";
return name;
}
public void getDo() {
super.getDo();
log.info("我还可以看天气预报!");
log.info("我还可以看新闻!");
}
}
运行一下:
public static void main(String[] args) {
Product product = new ProductImpl();
Product proxy = new ProductProxy(product);
log.info(proxy.getName());
proxy.getDo();
log.info("------------");
Product extend = new ProductProxyExtend();
log.info(extend.getName());
extend.getDo();
}
打印结果
15:27:38.992 [main] INFO demo.Demo - 我是一个产品,我是一个电视!我是星星品牌的大电视机,全球销量第一!世界最强
15:27:38.995 [main] INFO demo.ProductImpl - 我是电视!我可以播放奥特曼!
15:27:38.995 [main] INFO demo.ProductProxy - 我还可以看天气预报!
15:27:38.995 [main] INFO demo.ProductProxy - 我还可以看新闻!
15:27:38.995 [main] INFO demo.Demo - ------------
15:27:38.995 [main] INFO demo.Demo - 我是一个产品,我是一个电视!我是星星品牌的大电视机,全球销量第一!世界最强
15:27:38.995 [main] INFO demo.ProductImpl - 我是电视!我可以播放奥特曼!
15:27:38.995 [main] INFO demo.ProductProxyExtend - 我还可以看天气预报!
15:27:38.995 [main] INFO demo.ProductProxyExtend - 我还可以看新闻!
可以看到实现结果是一样的;
静态代理类优缺点
优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
缺点:
1)代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。