《设计模式》GOF 说明:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
package cn.google.design.adapter;
//目标角色, 开放给客户的接口 clientInterface
public interface Target {
public void clientInterface();
}
package cn.google.design.adapter;
//源角色
public class AdapterSource {
public AdapterSource() {}
public void sourceRole() {
System.out.println("sourceRole() ============");
}
}
package cn.google.design.adapter;
//适配器角色,将接口sourceRole()转化为给客户的接口clientInterface
public class Adapter implements Target{
//被代理的设备
private AdapterSource adapterSource;
//装入被代理的设备
public Adapter(AdapterSource adapterSource) {
super();
this.adapterSource = adapterSource;
}
@Override
public void clientInterface() {
adapterSource.sourceRole();
}
}
package cn.google.design.adapter;
/**
* 客户端
* Apapter模式使得原本由于接口不兼容而不能再一起工作的那些类可以一起工作
*/
public class Client {
public static void main(String[] args) {
AdapterSource as = new AdapterSource();
Target target = new Adapter(as);
target.clientInterface();
}
}
一、搬移函数
1、如果一个函数与所属类之外的一个类有更多的交流:调用和被调用,那么可以将该函数搬到那一个类中去,然后将旧函数变成一个委托函数或者删除。
2、有时候,可以将该函数所在的旧类的对象当新函数的参数。
二、搬移字段
1、如果一个字段被所属类之外的一个类更多地使用,可以将该字段搬移过去,君子好成人之美嘛!
2、可以采用自封装的办法搬移。
三、提炼类
1、如果一个类做了两个类做的事情,那么可以拆成两个类。一个人做两个人的事情,身体迟早要吃不消,类也是一样的。
2、并发编程常常采用。
四、将类内联化
1、如果一个类已经不再承担只够的责任,那么就把它干掉吧。毕竟太多的类不是一件好事。
2、将这个类的所有特性搬移到另一个类中,然后移除原类。
五、隐藏委托关系
1、如果客户通过一个委托类来调用另一个对象,可以在服务类上建立客户所需的所有函数,用以隐藏委托关系。
2、这样可以封装内部的细节,让客户不需要与被委托对象打交道。
六、移除中间人
1、和上面相反的情况,如果一个类做了过多恶简单委托动作,变成了一个中间人,那么还不如让客户直接调用受托类;
2、多了一个中间人,意味着受托类是一个改变中间类也额能要改变,所以需要移除中间人。
七、引入外加函数
1、如果需要一个你不能修改的类提供一个新的方法,那么可以在自己的类中建立一个方法,并以第一参数的形式传入一个服务类实例。
2、不过引入过多的外加函数不是一件好事,如果要引入的函数比较多,可以用第八条;
八、引入本地扩展
1、如果需要一个你不能修改的类提供多个新的方法,那么可以建立一个新类,让它实现这些新的方法。让这个新类成为不能修改的类恶子类和包装类;
2、这个新类提供源类的所有功能,并且实现新的功能,然后在任何使用源类的地方都使用新类。
3、第二点比较重要,不然会引起混乱。
1. 首先定义一个接口(JDK的动态代理就是建立在接口编程上,如果一个类没有实现借口,JDK就不会帮你产生对应的动态代理类。但是可以借助CGLIB来直接修改二进制码)
public interface UserDao {
public void save(User user);
public void delete(User user);
public void update(User user);
}
2. 接口的实现类(真实业务的实现)
public class UserDaoImpl implements UserDao {
public void delete(User user) {
System.out.println("删除用户成功。。。。");
}
public void save(User user) {
System.out.println("插入用户成功。。。。");
}
public void update(User user) {
System.out.println("更新用户成功。。。。");
}
}
3. 实现InVocationHandler接口的invoke()方法
public class LogHandler_old implements InvocationHandler {
// 组合的方式引入被代理对象
private Object target = null;
private static Logger logger = Logger.getLogger(LogHandler_old.class);
// 构造函数注入被代理对象
public LogHandler_old(Object target) {
this.target = target;
}
/*
* invoke 必须根据需要 Override
* Proxy.newProxyInstance(...)时候会自动调用这个invoke方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
logger.info(method.getName() + "开始执行。。。。");
Object result = method.invoke(target, args);
logger.info(method.getName() + "执行结束。。。。");
return result;
}
}
4. 创建Proxy对象,测试
public class ProxyTest_old {
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
LogHandler_old logHandler = new LogHandler_old(userDao);
UserDao userDaProxy = (UserDao) Proxy.newProxyInstance(userDao
.getClass().getClassLoader(), userDao.getClass()
.getInterfaces(), logHandler);
userDaProxy.delete(new User());
userDaProxy.save(new User());
userDaProxy.update(new User());
}
}
解释:
1. Proxy即动态代理类;
2. Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用;
它有三个参数:
ClassLoader loader ----指定被代理对象的类加载器
Class[] Interfaces ----指定被代理对象所以事项的接口
InvocationHandler h ----指定需要调用的InvocationHandler对象
3. 实现InVocationHandler接口的LogHandler_old对象
这个对象的invoke()方法就是Proxy这个动态代理类所代理的接口类的抽象方法的真实实现;
它有三个参数:
Object proxy -----代理类对象
Method method -----被代理对象的方法(这里不是接口的抽象方法了,是具体的实现类中的方法)
Object[] args -----该方法的参数数组
JDK中具体的动态代理类是怎么产生的呢?
1.产生代理类$Proxy0类
执行了Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
将产生$Proxy0类,它继承Proxy对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode,toString和equals三个方法),但是还没有具体的实现体;
2. 将代理类$Proxy0类加载到JVM中
这时候是根据Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第一个参数----就是被代理类的类加载器,把当前的代理类加载到JVM中
3. 创建代理类$Proxy0类的对象
调用的$Proxy0类的$Proxy0(InvocationHandler)构造函数,生成$