Java反射--反射与***模式
内容学习于:edu.aliyun.com
1. 静态***设计模式弊端
***设计模式最为核心的意义在于,所有的操作业务接口都设置两个子类,一个子类负责真实的业务实现,另外一个子类负责***业务操作,如果没有这个***业务,真实业务也无法进行处理。
现在假设说希望可以实现一个数据的处理操作,在进行数据处理的时候,要求进行合理的事务控制,在数据库里面永远都会存在有一个事务的概念,利用事务可以保证数据操作的完整性。
如下图所示:
编写传统***模式:
interface IMemberService{//实现用户数据操作
public void add();//实现用户数据追加
}
class MemberServiceImpl implements IMemberService{
@Override
public void add() {
System.out.println("【真实业务主题】向数据库添加数据");
}
}
class MemberServiceProxy implements IMemberService{
private IMemberService realSubject;//真实操作业务
public MemberServiceProxy(IMemberService realSubject){
this.realSubject = realSubject;
}
public boolean connect(){
System.out.println("【***主题】进行数据库的访问连接...");
return true;
}
public void close(){
System.out.println("【***主题】关闭数据库连接...");
}
public void transaction(){
System.out.println("【***主题】事务提交,进行数据更新处理");
}
@Override
public void add() {
if (this.connect()){
this.realSubject.add();
this.transaction();
this.close();
}
}
}
class Factor {
private Factor(){}
public static IMemberService getInstance(){
return new MemberServiceProxy(new MemberServiceImpl());
}
}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
IMemberService memberService = Factor.getInstance();
memberService.add();
}
}
结果:
【***主题】进行数据库的访问连接…
【真实业务主题】向数据库添加数据
【***主题】事务提交,进行数据更新处理
【***主题】关闭数据库连接…
但是现在需要进一步思考一个问题,在一个数据库里面,有可能会存在有上百张表,如果每一张数据表都存在有一个XxxService接口的时候,这个时候***就会泛滥,而且泛滥的结果会发现所有的***步骤几乎雷同。
所以之前的静态***设计模式设计上只能够满足于一个操作接口的需求,而无法满足于所有操作接口的需求(前提:操作的形式类似)。
2. 动态***设计模式
如果要想解决好静态***设计模式所存在的代码重复的操作问题,就只能够利用动态***设计模式来解决,而所谓的动态***设计模式指的是一组相关的操作接口的实现,可以设置统一的***类。
如下图所示:
动态***类是在JDK 1.3 的时候添加到项目之中的,如果要想实现动态***类需要“Invocation"接口和“Proxy类"的支持,首先来观察java.lang.reflect.InvocationHandle接口的定义:
- public interface InvocationHandler {public 0bject invoke (Object proxy, Method method, Object[] args) throws Throwable ;
此时对于***设计需要解决的一个核心问题在于,如何可以让InvocationHandler子类和要***操作的业务接口产生关联,所以此时就需要通过java.lang.eflect.Proxy类来进行关联的创建,创建关联的方法:
- public static Object newProxyInstance(ClassL oader loader, Class<?>[] interfaces, InvocationHandler h)
这种***对象的创建是依据真实主题类的对象的加载器,和其实现的父接口动态创建的一个新的子类,该子类由JVM在运行的时候自行负责创建。
如下图所示:
动态***模式:
interface IMemberService {//实现用户数据操作
public void add();//实现用户数据追加
}
class MemberServiceImpl implements IMemberService {
@Override
public void add() {
System.out.println("【真实业务主题】向数据库添加数据");
}
}
class ServiceProxy implements InvocationHandler {
private Object target;//真实操作业务
/** * 绑定真实主题对象,同时返回***实例 * @param target 真正的接口操作对象,利用反射可以追踪其来源 * @return ***对象 */
public Object bind(Object target){
this.target = target;//保存真实业务对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
public boolean connect() {
System.out.println("【***主题】进行数据库的访问连接...");
return true;
}
public void close() {
System.out.println("【***主题】关闭数据库连接...");
}
public void transaction() {
System.out.println("【***主题】事务提交,进行数据更新处理");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object returnValue = null;
if (this.connect()){
returnValue = method.invoke(this.target,args);//调用真实主题
this.transaction();
this.close();
}
return returnValue;
}
}
class Factor {
private Factor() {
}
public static IMemberService getInstance() {
return (IMemberService) new ServiceProxy().bind(new MemberServiceImpl());
}
}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
IMemberService memberService = Factor.getInstance();//得到一个jvm动态实例化子类对象
memberService.add();
}
}
结果:
【***主题】进行数据库的访问连接…
【真实业务主题】向数据库添加数据
【***主题】事务提交,进行数据更新处理
【***主题】关闭数据库连接…
此时的代码利用动态***设计类动态的构建了接口的实现子类实例,并且利用InvocationHandler.invoke(实现标准的代码执行调用,在里面进行***控制。
3. CGLIB实现动态***
现在已经实现了一个***设计,而且这种***设计是Java官方推荐的唯一实现机制,但是这种实现机制有部分开发人员认为有问题,在面向对象的角度来讲,不一定非要使用接口来进行标准的定义,有些人认为类应该可以作为标准型的定义形式,所以这类人觉得如下的代码设计不好:
- return Proxy. newProxyInstance(target. getClass (). getClassLoader(),
target. getClass (). getInterfaces(), this) ;
在使用Proxy类创建动态***类实例的时候必须要求有接口“target.getClass().getInterfaces()",所以有一部分不认可此设计的人员就依据自己的习惯设计了一个基于类的***操作,可以抛开接口存在的意义,实现***模式,于是这样的背景下就产生了一个第三方应用开发包“cglib" (cglib-nodep-3.2. 10.jar)。
通过cglib实现***:
class Message {
public void send(String msg) {
System.out.println("【真实业务】" + msg);
}
}
class MessageProxy implements MethodInterceptor {//cglib是基于***实现的
private Object target;//真实操作对象
public MessageProxy(Object target) {
this.target = target;
}
public boolean connect() {
System.out.println("【***主题】进行访问连接...");
return true;
}
public void close() {
System.out.println("【***主题】关闭连接...");
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object returnValue = null;
if (this.connect()) {
returnValue = method.invoke(this.target, objects);
this.close();
}
return returnValue;
}
}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
Message realObject = new Message();//真实业务主题
Enhancer enhancer = new Enhancer();//负责***控制的类
enhancer.setSuperclass(realObject.getClass());//模拟一个操作父类
enhancer.setCallback(new MessageProxy(realObject));//设置***对象
Message proxyObject = (Message) enhancer.create();//创建***对象,类似于proxy
proxyObject.send("www.mldn.cn");
}
}
此时的操作代码在没有实现父接口的情况下实现类的***设计,但是这样的设计只是一种传统JDK中的***操作实现的补充,可以利用其打破原始的设计要求。
<mark>一定要掌握Proxy + InvocationHandle接口的联合使用。</mark>