文章目录
1 代理模式(Proxy)
1.1 概念:
为其他对象提供一种代理以控制对这个对象的访问(对其他对象功能的增强)。在某些情况下,一个对象不适合或者不能直接引用另一个对象(委托类),而代理对象(代理类)可以在客户端和目标对象之间起到中介的作用。
1.2 特点:
1) 其特征是代理类与委托类有同样的接口(父类),代理类主要负责为委托类预处理信息(前置通知)、过滤信息(前置通知)、把消息转发给委托类(环绕通知),以及事后处理信息(后置,最终通知)等。
2) 代理类对象本身并不真正实现服务(真正做的业务,委托类需要干什么事),而是通过调用委托类的对象的相关方法,来提供特定的服务(对原服务的增强)。
现实中的实例: 1,明星(委托类),经纪人(代理类) 明星演出,演出是真正的业务, 围绕着演出(执行真正业务),经纪人要做一堆的事情,演出之前,预约,谈演出费,收预付款,确定演出时间,演出服装,演出具体内容,根据上面这些东西,再预定机票,酒店,准备道具,明星去演出(真正业务)经纪人要陪伴,防止突发事件,演出后收尾款,交税等相关事宜。。。。
2,普通客户(委托类)和银行职员(代理类) 超过6W取款,事先预约 ,事后干什么 3,房东/客户 (委托类) 房屋中介(代理类)
等等。。。
1.3 实现:
1)静态代理:
银行雇员代理客户执行相关银行服务
package com.aaa.dp.proxy.static1;
/**
* @ fileName:Account
* @ description: 委托类和代理类拥有的共同接口
* @ author:zhz
* @ createTime:2021/12/3 9:56
* @ version:1.0.0
*/
public interface Account {
/**
* 查询余额
*/
void query();
/**
* 存取钱
* @param money
*/
void updateMoney(double money);
}
package com.aaa.dp.proxy.static1;
/**
* @ fileName:Client
* @ description: 委托类(银行客户)
* @ author:zhz
* @ createTime:2021/12/3 9:58
* @ version:1.0.0
*/
public class Client implements Account {
@Override
public void query() {
System.out.println("。。。。。。。。。。XXX查询了余额......顿时不热了.....");
}
@Override
public void updateMoney(double money) {
System.out.println("。。。。。。。。。。XXX存取了"+money+"钱");
}
}
package com.aaa.dp.proxy.static1;
/**
* @ fileName:Employee
* @ description:代理类(银行雇员)
* @ author:zhz
* @ createTime:2021/12/3 9:59
* @ version:1.0.0
*/
public class Employee implements Account{
//委托类
private Client client;
/**
* 通过构造 给委托类赋值 (也可以通过set方法)
* @param client
*/
public Employee(Client client) {
this.client = client;
}
@Override
public void query() {
System.out.println("查询余额前做什么准备。。。。。。");
//委托类执行真正的业务
client.query();
System.out.println("查询余额后做什么工作。。。。。。");
}
@Override
public void updateMoney(double money) {
System.out.println("存取前做什么准备。。。。。。");
//委托类执行真正的业务
client.updateMoney(money);
System.out.println("存取后做什么工作。。。。。。");
}
}
package com.aaa.dp.proxy.static1;
/**
* @ fileName:Test
* @ description:
* @ author:zhz
* @ createTime:2021/12/3 10:05
* @ version:1.0.0
*/
public class Test {
public static void main(String[] args) {
Client client =new Client();
Employee employee =new Employee(client);
employee.query();
employee.updateMoney(100000);
}
}
2)JDK动态代理:
java.lang.reflect包下提供了一个Proxy类和一个Invocationhandler接口,用来完成动态代理。
Invocationhandler接口:
当我们通过代理对象调用一个方法时,这个方法的调用就会被转发为由Invocationhandler这个接口的invoke方法进行调用。
Object invoke(Object proxy,Method method ,Object[] args)
参数:Object proxy:指被代理的对象
Method method: 要调用的方法
Object[] args: 方法调用时所需的参数
Proxy类:
该类提供了一个创建动态代理对象的方法。
static Object newProxyInstance(ClassLoader loader ,Class<?>[] interfaces,InvocationHandler h);
参数:
ClassLoader loader:定义代理类的类加载器。
Class<?>[] interfaces: 代理类要实现的接口列表
InvocationHandler h: 指派方法调用的调用处理程序 表示代理对象要关联的InvocationHandler对象。
package com.aaa.dp.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @ fileName:JDKProxy
* @ description:jdk代理类 可以代理任意委托类
* @ author:zhz
* @ createTime:2021/12/3 10:42
* @ version:1.0.0
*/
public class JDKProxy implements InvocationHandler {
//委托类
private Object obj;
/**
* 给委托类赋值,返回代理类对象
* @param obj
* @return
*/
public Object bindObj(Object obj){
this.obj=obj;
//通过反射获取委托类的所有接口
Class<?>[] interfaces = this.obj.getClass().getInterfaces();
//参数1 类加载器 参数2
return Proxy.newProxyInstance(
JDKProxy.class.getClassLoader(),
interfaces,
this);
}
/**
*
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
String methodName = method.getName();
System.out.println("方法名称为:"+methodName);
/* if("query".equals(methodName)) {
System.out.println("查询余额前做什么准备。。。。。。");
result = method.invoke(this.obj, args);
System.out.println("查询余额后做什么工作。。。。。。");
}else if("updateMoney".equals(methodName)){
System.out.println("存取前做什么准备。。。。。。");
result = method.invoke(this.obj, args);
System.out.println("存取后做什么工作。。。。。。");
}*/
System.out.println("事前做什么准备。。。。。。");
result = method.invoke(this.obj, args);
System.out.println("事后做什么工作。。。。。。");
return result;
}
}
package com.aaa.dp.proxy.jdk;
import java.util.List;
/**
* @ fileName:DeptService
* @ description:
* @ author:zhz
* @ createTime:2021/12/3 11:03
* @ version:1.0.0
*/
public interface DeptService {
/**
* 修改方法
* @param o
* @return
*/
int update(Object o);
/**
* 添加方法
* @param o
* @return
*/
int add(Object o);
/**
* 删除方法
* @param id
* @return
*/
int deleteById(int id);
/**
* 分页带参查询
* @param str
* @return
*/
List<Object> queryAll(String ...str);
}
package com.aaa.dp.proxy.jdk;
import java.util.List;
/**
* @ fileName:DeptServiceImpl
* @ description:
* @ author:zhz
* @ createTime:2021/12/3 11:06
* @ version:1.0.0
*/
public class DeptServiceImpl implements DeptService {
@Override
public int update(Object o) {
System.out.println("................模拟更新。。。");
return 0;
}
@Override
public int add(Object o) {
System.out.println("................模拟添加。。。");
return 0;
}
@Override
public int deleteById(int id) {
System.out.println("................模拟删除。。。");
return 0;
}
@Override
public List<Object> queryAll(String... str) {
System.out.println("................模拟查询。。。");
return null;
}
}
测试:
package com.aaa.dp.proxy.jdk;
import com.aaa.dp.proxy.static1.Account;
/**
* @ fileName:TestA
* @ description:
* @ author:zhz
* @ createTime:2021/12/3 11:07
* @ version:1.0.0
*/
public class TestA {
public static void main(String[] args) {
//委托类
DeptService deptService =new DeptServiceImpl();
//实例化代理类
JDKProxy jdkProxy = new JDKProxy();
//返回当前委托类接口的子类 (代理类) 多态
DeptService deptServiceResult = (DeptService)jdkProxy.bindObj(deptService);
deptServiceResult.add("1");
deptServiceResult.update("1");
deptServiceResult.deleteById(1);
deptServiceResult.queryAll();
}
}
3)CGLIB(Code Generation Library)动态代理:
maven依赖:
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
主要应用于没有接口的动态代理生成(主要是对指定的类生成一个子类,覆盖其中的所有方法,所以该类或方法不能声明称final的。), spring AOP框架,Hibernate都使用了CGLLIB。
net.sf.cglib.proxy.Enhancer类:允许为非接口类型创建一个Java代理。Enhancer动态创建了给定类型的子类,并拦截了所有的方法。
(setSuperclass,setCallback,create)
net.sf.cglib.proxy.Callback接口:在CGLIB包中是一个很关键的接口,所有被net.sf.cglib.proxy.Enhancer类调用的回调(callback)接口都要继承这个接口。
举例说明回调:
net.sf.cglib.proxy.MethodInterceptor接口:是最通用的回调(callback)类型,它经常被AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法。
public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy)
proxy:代理的对象;method:委托类执行的方法;params:方法中的参数; methodProxy:代理的方法
由于性能的原因,对原始方法的调用我们使用CGLIB的net.sf.cglib.proxy.MethodProxy对象,而不是反射中一般使用java.lang.reflect.Method对象
实现代码:
package com.aaa.dp.proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @ fileName:CGLibProxy
* @ description:
* @ author:zhz
* @ createTime:2021/12/3 11:21
* @ version:1.0.0
*/
public class CGLibProxy implements MethodInterceptor {
//委托类
private Object obj;
/**
* 给委托类赋值,并生成委托类的代理类
* @param obj
* @return
*/
public Object bindObj(Object obj){
this.obj =obj;
Enhancer enhancer =new Enhancer();
//设置生成代理类的父类
enhancer.setSuperclass(this.obj.getClass());
//生成委托类的子类后,用Callback调用子类的所有方法
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result = null;
System.out.println("事前做什么准备。。。。。。");
result = methodProxy.invoke(this.obj,objects);
System.out.println("事后做什么工作。。。。。。");
return result;
}
}
package com.aaa.dp.proxy.cglib;
import com.aaa.dp.proxy.jdk.DeptService;
import java.util.List;
/**
* @ fileName:DeptServiceImpl
* @ description:
* @ author:zhz
* @ createTime:2021/12/3 11:06
* @ version:1.0.0
*/
public class DeptServiceImpl implements DeptService {
public final int update(Object o) {
System.out.println("................模拟更新。。。");
return 0;
}
public int add(Object o) {
System.out.println("................模拟添加。。。");
return 0;
}
public int deleteById(int id) {
System.out.println("................模拟删除。。。");
return 0;
}
public List<Object> queryAll(String... str) {
System.out.println("................模拟查询。。。");
return null;
}
}
package com.aaa.dp.proxy.cglib;
/**
* @ fileName:Test
* @ description:
* @ author:zhz
* @ createTime:2021/12/3 11:28
* @ version:1.0.0
*/
public class Test {
public static void main(String[] args) {
DeptServiceImpl deptService =new DeptServiceImpl();
CGLibProxy cgLibProxy =new CGLibProxy();
DeptServiceImpl deptServiceResult = (DeptServiceImpl)cgLibProxy.bindObj(deptService);
deptServiceResult.add("1");
deptServiceResult.update("1");
deptServiceResult.deleteById(1);
deptServiceResult.queryAll();
}
}
如果目标对象没有实现接口,则默认会采用CGLIB代理;
如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class=“true”/>)。
CGLib动态代理创建代理实例速度慢,但是运行速度快;JDK动态代理创建实例速度快,但是运行速度慢。如果实例是单例的,推荐使用CGLib方式动态代理,反之则使用JDK方式进行动态代理。Spring的实例默认是单例,所以这时候使用CGLib性能高。
2 观察者模式(Observer Pattern)
2.1 定义
观察者模式 是软件设计模式的一种。 它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。在观察者模式中,监视另一个对象状态的对象称为Observer,正在被监视的对象称为Subject。
2.2 现实例子
例如,某种商品的物价上涨时会导致部分商家高兴,而消费者伤心;还有,当我们开车到交叉路口时,遇到红灯会停,遇到绿灯会行。这样的例子还有很多,例如,股票价格与股民、微信公众号与微信用户、气象局的天气预报与听众、小偷与警察等。
2.3 角色
1)、抽象主题(Subject):
它把所有观察者对象的引用保存到一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
2)、具体主题(Concrete Subject):
将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
3)、抽象观察者(Observer):
为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
4)、具体观察者(Concrete Observer):
实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
2.4 实现
被观察者接口:
package com.aaa.dp.observer;
/**
* @ fileName:Subject
* @ description:
* @ author:zhz
* @ createTime:2021/12/3 11:43
* @ version:1.0.0
*/
public interface Subject {
/**
* 注册观察者
*/
void registerObserver(Observer observer);
/**
* 移除观察者
* @param observer
*/
void removeObserver(Observer observer);
/**
* 通知所有观察者
* @param message
*/
void notifyObserver(String message);
}
被观察者实现:
package com.aaa.dp.observer;
import java.util.ArrayList;
import java.util.List;
/**
* @ fileName:ConcreteSubject
* @ description:
* @ author:zhz
* @ createTime:2021/12/3 11:45
* @ version:1.0.0
*/
public class ConcreteSubject implements Subject {
//所有观察者集合
private List<Observer> observerList = new ArrayList<>();
@Override
public void registerObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyObserver(String message) {
if(observerList!=null&&observerList.size()>0){
for (Observer observer : observerList) {
observer.update(message);
}
}
}
}
观察者接口:
package com.aaa.dp.observer;
/**
* @ fileName:Observer
* @ description:
* @ author:zhz
* @ createTime:2021/12/3 11:44
* @ version:1.0.0
*/
public interface Observer {
/**
* 根据主题变化,观察者也发生变化
* @param message
*/
void update(String message);
}
观察者实现:
package com.aaa.dp.observer;
/**
* @ fileName:ConcreteObserver
* @ description:
* @ author:zhz
* @ createTime:2021/12/3 11:49
* @ version:1.0.0
*/
public class ConcreteObserver implements Observer {
//观察者名称
private String obName;
public ConcreteObserver(String obName) {
this.obName = obName;
}
@Override
public void update(String message) {
System.out.println("观察者"+obName+"根据"+message+"变化,自己做了什么什么调整。。。。");
}
}
测试:
package com.aaa.dp.observer;
/**
* @ fileName:Test
* @ description:
* @ author:zhz
* @ createTime:2021/12/3 11:50
* @ version:1.0.0
*/
public class Test {
public static void main(String[] args) {
//实例化OB
Observer observer1 =new ConcreteObserver("ob1");
Observer observer2 =new ConcreteObserver("ob2");
Observer observer3 =new ConcreteObserver("ob3");
Observer observer4 =new ConcreteObserver("ob4");
//实例化Subject
Subject subject =new ConcreteSubject();
subject.registerObserver(observer1);
subject.registerObserver(observer2);
subject.registerObserver(observer3);
subject.registerObserver(observer4);
//主题变化
subject.notifyObserver("变黄了");
System.out.println("----------------------------------");
//移除OB
subject.removeObserver(observer1);
subject.notifyObserver("变红了");
}
}
2.5 好处
观察者模式将观察者和主题(被观察者)彻底解耦,主题只知道观察者实现了某一接口(也就是Observer接口)。并不需要观察者的具体类是谁、做了些什么或者其他任何细节。任何时候我们都可以增加新的观察者。因为主题唯一依赖的东西是一个实现了Observer接口的对象列表。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/75496.html