动态代理和装饰者模式的理解 (和Integer中添加String的方法)

动态代理:

先来看看代理的引入:

代理就是在程序的执行过程中,通过一个类Proxy和接口invacationHandler(处理程序)实现动态代理

 

先创建一个接口里面有我们需要的方法(就是我们需要代理的对象)

package com.westos.InvocationHandler;
/**
 * 来实现一个增删改查的代理
 *
 */
public interface UserDao {
 
public abstract void add();//增加
public abstract void delete();//删除
public abstract void modify();//修改
public abstract void find();//查询

}

 

 

再去创建一个它的子实现类去实现它的方法:

 

package com.westos.InvocationHandler;
 
public class UserDaoImpl implements UserDao{
 
@Override
public void add() {
System.out.println("调用了增加功能");
}
 
@Override
public void delete() {
System.out.println("调用了删除功能");
}
 
@Override
public void modify() {
System.out.println("调用了修改功能");
}
 
@Override
public void find() {
System.out.println("调用了查询功能");
}
}

 

创建一个子实现类去实现InvocationHandler代理接口

package com.westos.InvocationHandler;
/**
 * 创建一个子实现类去实现InvocationHandler代理接口
 */
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
 
public class MyInvocationHandler implements InvocationHandler {
 
//我们首先定义一个需要代理的对象
private Object target;

//创建该类的有参构造
public MyInvocationHandler (Object target) {
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//实现代理的程序
//invoke方法就是实现代理的方法
System.out.println("权限校验");
Object obj = method.invoke(target, args);
System.out.println("日志记录");
return obj;
}
 
}

 

最后创建一个测试类:

package com.westos.InvocationHandler;
 
import java.lang.reflect.Proxy;
 
public class UserTest {
 
public static void main(String[] args) {

//创建UserDao对象,使用多态的形式
UserDao ud=new UserDaoImpl();
ud.add();
ud.delete();
ud.modify();
ud.find();

System.out.println("-----------------------------");

//创建MyInvocationHandler类对象
MyInvocationHandler handler=new MyInvocationHandler(ud);

/**
 * 我们需要代理的对象时UserDao接口
 * 所以下面的newProxyInstance方法中的对象就是UserDao接口的对象
 * loader:就是代理对象先获取字节码文件再去获取它的类加载器类(loader)
 * interfaces:就是代理对象所表示的类或接口所实现的接口
 * 同样是先获取字节码文件再去调用getInterfaces()方法
 * h:就是InvocationHandler接口本身或者他的子实现类对象
 */

//以为这里的代理对象时UserDao所以我们需要将类型强制转化成UserDao类型
UserDao ud2 = (UserDao)Proxy.newProxyInstance(ud.getClass().getClassLoader(), ud.getClass().getInterfaces(), handler);
ud2.add();
ud2.delete();
ud2.modify();
ud2.find();
}
}
 
运行结果:
调用了增加功能
调用了删除功能
调用了修改功能
调用了查询功能
-----------------------------
权限校验
调用了增加功能
日志记录
权限校验
调用了删除功能
日志记录
权限校验
调用了修改功能
日志记录
权限校验
调用了查询功能
日志记录

 

装饰者模式的认识:

装饰者模式就是创建一个装饰抽象类,然后再去创建两个子类去装饰需要装饰的对象

需求:

一个手机可以打电话,我们可以去实现它的打电话功能,但是我们想额外给它装饰一些打电话之前听彩铃和打完电话听音乐的功能,这就是我们需要去了解的

 

例如:

先创建一个手机接口,定义打电话功能:

package com.westos.Decorate;
 
public interface Phone {
 
public abstract void call();

}

 

再创建一个子实现去实现它的打电话功能

package com.westos.Decorate;
 
public class PhoneImpl implements Phone {
 
@Override
public void call() {
 
System.out.println("可以打电话了...");
}

 
}

 

然后我们就去创建一个抽象的装饰类,记住是抽象的

package com.westos.Decorate;
/**
 * 这是一个手机的修饰类
 */
public abstract class PhoneDecorate implements Phone {

//创建私有化Phone类对象
private Phone p;

//创建该类的有参构造
public PhoneDecorate(Phone p) {
this.p=p;
}
 
@Override
public void call() {
 
//这里的this代表了当前的类,调用了call方法,因为存在继承关系,所以还是在访问Phone的方法
this.p.call();
}
 
}

 

再去创建两个子类去继承装饰类,并且加入他们想要装饰的功能:

 

package com.westos.Decorate;
/**
 * 装饰上了听彩铃的功能
 * 因为该类是继承了PhoneDecorate类,所以需要重写父类的构造方法和成员方法
 */
public class RingPhoneDecorate extends PhoneDecorate {
 
public RingPhoneDecorate(Phone p) {
super(p);
}
 
@Override
public void call() {
System.out.println("手机可以听彩铃了...");
super.call();
}

}

 

package com.westos.Decorate;
/**
 * 装饰上了听音乐的功能
 */
public class MusicPhoneDecorate extends PhoneDecorate {
 
public MusicPhoneDecorate(Phone p) {
super(p);
}
 
@Override
public void call() {

super.call();
System.out.println("手机可以听音乐了...");
}
}

 

 

最后写一个测试类去测试这些功能:

 

 

package com.westos.Decorate;

public class Test {

	public static void main(String[] args) {

		// 创建Phone类对象
		Phone p = new PhoneImpl();
		p.call();
		System.out.println("------------------");
		/**
		 * 需求:先听彩铃再打电话
		 */
		// 创建手机修饰类对象
		PhoneDecorate pd = new RingPhoneDecorate(p);
		pd.call();
		System.out.println("---------------------");

		/**
		 * 需求:先听彩铃再打电话然后听音乐
		 */
		pd = new RingPhoneDecorate(new MusicPhoneDecorate(p));
		pd.call();
	}
}
运行结果:
可以打电话了...
------------------
手机可以听彩铃了...
可以打电话了...
---------------------
手机可以听彩铃了...
可以打电话了...
手机可以听音乐了...


确定Integer类型后如何添加String类型的练习:

 

我们之前学习泛型确定了集合的类型后就不能再添加其他类型的数据,那么有这样一个问题:

 

我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?

 

例如:

package com.westos.ReflectTest;
 
import java.lang.reflect.Method;
import java.util.ArrayList;
 
//我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
public class ReflectTest {
 
public static void main(String[] args) throws Exception {

//创建一个ArrayList集合对象
ArrayList<Integer> list=new ArrayList<Integer>();

/**
 * 直接用add方法添加是有异常的,所以我们可以通过反射 的方法去解决
 */
list.add(23);
// list.add("hello");

//我们可以观看底层源码是通过add方法去添加的(add(E e))
/**
 * 用第一种方法获取ArrayList集合的字节码文件对象
 * 下面的Object.class为了能够添加字符串属性,所以换成Object
 */
Class c = list.getClass();
Method method = c.getMethod("add", Object.class);
//
method.invoke(list, "hello");
method.invoke(list, "world");
System.out.println(list);
}
}
 
运行结果:
[23, hello, world]

这里我们只是了解可以有这样的方法完成我们的需求,但是一般还是按正常的泛型步骤来写

猜你喜欢

转载自blog.csdn.net/j_better/article/details/80600242