设计模式之结构性模式(一)
一、适配器模式
二、代理模式
核心作用:从程序的结构上实现松耦合,从而可以扩大整体的类结构,解决更大的问题
分类:适配器模式、代理模式、桥接模式、装饰模式、组合模式、外观模式、享元模式
一、适配器模式
将一个类的接口转换成客户希望的另一个接口,可以使原本由于接口不兼容而不能一起工作的类可以一起工作
模式中的角色:
目标接口(Target):客户所期待的接口,目标可以是具体的或抽象的类,也可以是接口
需要适配的类(Adaptee):需要适配的类或适配者的类
适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口
实例:电脑(Client) 转换器(Adapter) 键盘(Adaptee)
Adaptee
/**
* 被适配的类(相当于键盘)
*/
package com.adapter;
public class Adaptee {
//需求
public void request() {
System.out.println("可以完成客户端请求需要的功能");
}
}
Adapter(类适配器)
/**
* 适配器(相当于转接器,USB)
*/
package com.adapter;
public class Adapter extends Adaptee implements Target{
@Override
public void handleRequest() {
super.request();
}
}
Target
//目标接口
package com.adapter;
public interface Target {
//处理需求的方法
public void handleRequest();
}
Adapter2(对象是适配器)
/**
* 适配器(相当于转接器)
*/
package com.adapter;
public class Adapter2 implements Target {
Adaptee adaptee;
public Adapter2(Adaptee adaptee) {
super();
this.adaptee = adaptee;
}
@Override
public void handleRequest() {
adaptee.request();
}
}
Client
/**
* 客户端类(相当于笔记本,只有USB接口)
*/
package com.adapter;
public class Client {
public void test(Target t) {
t.handleRequest();
}
public static void main(String[] args) {
Client laptop = new Client();//电脑(客户端)
Adaptee keyboard = new Adaptee();//键盘(适配的类)
//Target adapter = new Adapter();//适配器(转换器)
Target adapter = new Adapter2(keyboard);//适配器(转换器)
laptop.test(adapter);
}
}
结果:
可以完成客户端请求需要的功能
二、代理模式
核心作用:通过代理,控制对对象的访问
可以详细控制访问某个对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理(AOP的微观实现)
AOP:Aspect Oriented Progrmming 面向切面编程的核心机制
核心角色:
抽象角色:定义代理角色和真实角色的公共对外方法
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用(关注真正的业务逻辑)
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作(将统一的流程控制放到代理角色中处理)
应用场景:
安全代理:屏蔽对真实角色的直接访问
远程代理:通过代理类处理远程方法调用(RMI)
延时加载:先加载轻量级的代理对象,真正需要再加载真实对象
(比如开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有100MB,在打开文件时,不可能将所有文件都显示出来,这样就可以使用代理模式,当需要查看图片时,用proxy来进行大图片的打开)
分类:
静态代理(静态定义代理类)
动态代理(动态定义代理类)
1)JDK自带的动态代理
2)javaassist字节码操作库实现
3)CGLIB
4)ASM(底层使用指令,可维护性较差)
静态代理类
实例:明星 明星代理人
Star
/**
* 明星接口
*/
package com.proxy.staticProxy;
public interface Star {
public void confer();//面谈
public void signContract();//签合同
public void bookTicket();//订机票
public void sing();//唱歌
public void collectMoney();//收钱
}
RealStar
/**
* 明星本人
*/
package com.proxy.staticProxy;
public class RealStar implements Star {
@Override
public void confer() {
System.out.println("RealStar.confer()");
}
@Override
public void signContract() {
System.out.println("RealStar.signContract()");
}
@Override
public void bookTicket() {
System.out.println("RealStar.bookTicket()");
}
@Override
public void sing() {
System.out.println("RealStar.sing()(明星本人)");
}
@Override
public void collectMoney() {
System.out.println("RealStar.collectMoney()");
}
}
ProxyStar
/**
* 明星代理人
*/
package com.proxy.staticProxy;
public class ProxyStar implements Star {
@Override
public void confer() {
System.out.println("ProxyStar.confer()");
}
@Override
public void signContract() {
System.out.println("ProxyStar.signContract()");
}
@Override
public void bookTicket() {
System.out.println("ProxyStar.bookTicket()");
}
@Override
public void sing() {
System.out.println("RealStar.sing()");
}
@Override
public void collectMoney() {
System.out.println("ProxyStar.collectMoney()");
}
}
Client
/**
* 测试函数
*/
package com.proxy.staticProxy;
public class Client {
public static void main(String[] args) {
Star realStar = new RealStar();
Star proxyStar = new ProxyStar();
proxyStar.confer();
proxyStar.bookTicket();
proxyStar.signContract();
proxyStar.collectMoney();
proxyStar.sing();
}
}
结果
ProxyStar.confer()
ProxyStar.bookTicket()
ProxyStar.signContract()
ProxyStar.collectMoney()
RealStar.sing()//注意
动态代理类
JDK自带的动态代理
Star
RealStar
StarHandler
package dynasticProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class StarHandler implements InvocationHandler {//处理器接口
//创建真实的明星
Star realStar = null;
//构造器
public StarHandler(Star realStar) {
super();
this.realStar = realStar;
}
//通过invoke()方法实现对真实角色的代理访问
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = null;
System.out.println("真正的方法执行前");
System.out.println("面谈、签合同、待付款、订机票");
//如果是sing,就调用realStar()方法
if(method.getName().equals("sing")) {
object = method.invoke(realStar, args);
}
System.out.println("真正的方法执行后");
System.out.println("收尾款");
return object;
}
}
Client
package dynasticProxy;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
Star realStar = new RealStar();
StarHandler handler = new StarHandler(realStar);
//每次通过Proxy生成代理类处理对象时,都要指定对应的处理器对象
Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{Star.class} ,handler );
proxy.sing();
}
}
结果:
真正的方法执行前
面谈、签合同、待付款、订机票
RealStar.sing()(明星本人)
真正的方法执行后
收尾款
代理模式开发框架中应用场景:
数据库连接池关闭处理
mybatis中实现拦截器插件
Aspect的实现
String中AOP的实现(日志拦截、声明式事务处理)
web service
RMI远程方法调用
面向切面编程常用术语:
切面:共有功能的实现
通知:切面的具体实现
连接点:程序在运行过程中能够插入切面的地点
切入点:用于定义应该切入到那些连接点上
目标对象:即将切入切面的对象,即被通知的对象
代理对象L:通知应用到目标对象之后被动态创建的对象
织入:将切面应用到目标对象从而创建一个新的代理对象的过程