下面我们通过同一个需求来对三种模式的讲解:
继承就不用多讲了,我们直接上代码
需求:有一个Winter(侍者),它有server(服务)功能,我们需要这个Winter对象增加两个功能[ welcome(欢迎) goodBye(再见)]
/**
* 侍者
*/
class Winter{
public void server(){
System.out.println("服务...");
}
}
/**
* 男侍者 继承侍者类
*/
class ManWinter extends Winter{
//增加功能
public void welcome(){
System.out.println("欢迎光临...");
}
public void goodBye(){
System.out.println("再见...");
}
}
/**
* 测试
*/
public class Test{
public static void main(String[] args) {
ManWinter winter = new ManWinter(); //创建一个男侍者对象
winter.welcome();
winter.server();
winter.goodBye();
}
}
运行结果:
欢迎光临...
服务...
再见...
可见达到了扩展功能的目的。
缺点:
1)被扩展功能的类(Winter类)是不能修改的(写死的)。
2) 扩展功能的类(ManWinter类)是不能修改的(写死的)。
这两个限制,使我们用起来十分的不方便(都不能修改,就不够灵活)。
这时候我们为了提供更方便的开发模式,就要想,能不能将被扩展功能的类(Winter类)变成可以改变的?
答案当然是能,这就出现了下面的装饰者模式。
装饰者模式:字面意思,对某东西进行装饰。 这里的意思是对被扩展功能类进行装饰(增加功能)。
FileInputStream fis = new FileInputStream("F:/a.jpg"); //创建一个文件输出流对象
BufferedInputStream b = new BufferedInputStream(fis); //给流添加缓冲区功能
ObjectInputStream o = new ObjectInputStream(b); //给流添加对象序列化功能
上面就是通过装饰者模式来完成的给文件输出流对象添加功能(缓冲区功能,对象序列化功能)的操作。
下面我们通过装饰者模式来自己设计:
需求: 有一个Winter(侍者),它有server(服务)功能,我们需要这个Winter对象增加两个功能[ welcome(欢迎) goodBye(再见)]
装饰者有一个小口诀:是你(is a)还有你(has a),一切拜托你(user a)
/**
* 侍者
*/
interface Winter{
public void server(); //侍者原有方法
}
/**
* 男侍者 (这里以男侍者为例,凡是Winter的子类对象都可以被MyDecorate装饰)
*/
class ManWinter implements Winter{
@Override
public void server() {
System.out.println("服务");
}
}
/**
* 侍者装饰类 是你还有你,一切拜托你
*/
class MyDecorate implements Winter{ //是你(MyDecorate本身是一个Winter的子类对象)
//这是底层对象,被增强的对象
private Winter winter; //还有你(MyDecorate中有Winter的实例化对象)
public MyDecorate(Winter winter){ //通过构造器传递底层对象!
this.winter = winter;
}
//一切拜托你(不是增强的地方,就让winter来完成)
@Override
public void server() {
winter.server();
}
/*
* 增强点 (这里就是要增强的功能)
*/
public void welcome(){
System.out.println("欢迎...");
}
public void goodBye(){
System.out.println("再见...");
}
}
/**
* 测试
*/
public class Test{
public static void main(String[] args) {
ManWinter manWinter = new ManWinter(); //创建男侍者对象
/*
* 创建一个装饰者对象,将男侍者传递给装饰者对象
* (要执行【一切拜托你】的操作)
*
* 现在这个装饰者对象就增加了两个方法(welcome()和goodBye())
* 达到了增强功能的目的
*/
//所有Winter的子类对象都可以被MyDecorate所装饰
MyDecorate myDecorate = new MyDecorate(manWinter);
myDecorate.welcome();
myDecorate.server();
myDecorate.goodBye();
}
}
执行结果:
欢迎光临...
服务...
再见...
整理一下整体思路:
1) 创建一个Winter接口
2) 创建一个实现Winter接口了的ManWinter类
3) 创建一个装饰类MyDecorate
4)测试:
● 创建一个被增强对象(Winter的子类对象)
● 创建一个装饰类对象(MyDecorate)
● 将Winter的子类对象(manWinter)传递给装饰类(MyDecorate)构造器
● 最终得到了一个装饰对象,这个对象就有了增强的方法welcome()和goodBye()
看到了这里,你可以再看一下上面的缓冲区装饰文件输入流的代码,应该可以发现具体步骤是一样的。对比一下:
//给文件输入流对象增加缓冲区功能
FileInputStream fis = new FileInputStream("f:/1.txt");
BufferedInputStream buf = new BufferedInputStream(fis);
//给manWinter增加功能
ManWinter manWinter = new ManWinter();
MyDecorate myDecorate = new MyDecorate(manWinter);
优点:被扩展功能的类是可以修改的(想要装饰哪个对象,就将这个对象传入装饰类的构造方法中,得到装饰对象,这个装饰对象就有需要增强的功能 注意:只能传入与装饰类实现了同一接口的对象)。
缺点:扩展功能的类(MyDecorate类)是不能修改的(也就是要增强的功能,是写死的)。
装饰者模式什么时候用呢? 在不知道被增强对象的具体类型时,就可以使用装饰者模式!
那么问题来了,能不能将扩展功能的类也变为可修改的(或者说是可选择的)呢?答案肯定是:可以的 这就有了下面的动态代理模式。
获取此类对象的方法:static Object newProxyInstance(ClassLoader loader, Class>[] interfaces, InvocationHandler h)
参数介绍:详细可查阅JDK API
● ClassLoader loader :类加载器,负责加载类的对象。
● Class>[] interfaces :接口数组,里面存放的都是目标对象实现的接口们的Class
● InvocationHandler h :java.lang.reflect.InvocationHandler是代理实例的调用处理程序 实现的接口。
此接口下的唯一抽象方法:Object invoke(Object proxy , Method method , Object[] args)
参数介绍:详细可查阅JDK API
● Object proxy :目标对象(需要被增强的对象)
● Method method :对应于在代理实例上调用的接口方法的Method实例
● Object[] args :包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为null
这里的类和参数介绍如果看不懂没关系,我们直接上代码,看完代码再返回这里更深入的理解。
需求: 有一个Winter(侍者),它有server(服务)功能,我们需要这个Winter对象增加两个功能[ welcome(欢迎)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 侍者
*/
interface Winter{
public void server();
}
/**
* 前置增强
*/
interface Before{
public void before();
}
/**
* 后置增强
*/
interface After{
public void after();
}
/**
* 动态代理工厂
*/
class ProxyFactory{
private Object targetObject; //目标对象 被增强对象
private Before before; //前置对象
private After after; //后置对象
/**
* 创建动态代理对象
* @return 动态代理对象
*/
public Object createProxy(){
/*
* 1.给出三大参数
*/
ClassLoader loader = this.getClass().getClassLoader(); //得到类加载器
Class[] interfaces = targetObject.getClass().getInterfaces(); //得到目标对象实现的接口们
InvocationHandler h = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(before != null) //如果前置对象不为空
before.before(); //调用前置对象的方法
Object result = method.invoke(targetObject, args); //调用目标对象的方法
if(after != null) //如果后置对象不为空
after.after(); //调用后置对象的方法
return result; //返回调用目标对象的方法得到的结果
}
};
/*
* 2.通过三大参数创建动态代理对象
*/
Object proxyObject = Proxy.newProxyInstance(loader, interfaces, h);
return proxyObject;
}
public Object getTargetObject() {
return targetObject;
}
public void setTargetObject(Object targetObject) {
this.targetObject = targetObject;
}
public Before getBefore() {
return before;
}
public void setBefore(Before before) {
this.before = before;
}
public After getAfter() {
return after;
}
public void setAfter(After after) {
this.after = after;
}
}
/**
* 测试
*/
public class Test{
public static void main(String[] args) {
//1.创建动态代理工厂对象
ProxyFactory factory = new ProxyFactory();
//2.设置目标对象
Winter targetObject = new Winter(){ //创建目标对象
@Override
public void server() {
System.out.println("服务...");
}};
factory.setTargetObject(targetObject);
//3.设置前置增强对象
Before before = new Before() {
@Override
public void before() {
System.out.println("欢迎光临...");
}
};
factory.setBefore(before);
//4.设置后置增强对象
After after = new After() {
@Override
public void after() {
System.out.println("再见...");
}
};
factory.setAfter(after);
//5.得到动态代理对象
Object proxyObject = factory.createProxy();
//6.将动态代理对象强转为目标对象类型
Winter winterObject = (Winter) proxyObject;
//7.调用目标对象方法
winterObject.server();
}
}
代码执行结果:
欢迎光临...
服务...
再见...
整理一下思路:
1)创建一个目标对象所实现的接口
2)创建一个前置增强对象所实现的接口
3)创建一个后置增强对象所实现的接口
4)创建一个动态对象工厂类:
● 创建 目标对象、前置增强对象、后置增强对象
● 得到三大参数(Proxy.newProxyInstance()所需要的参数) 现在可以到上面去再看一下类与参数介绍
● 创建动态代理对象
5)测试:
● 创建动态代理工厂对象
● 创建并设置 目标对象、前置增强对象、后置增强对象
● 通过动态代理工厂的createProxy()方法获得最终的动态代理对象
优点:
1)被扩展功能的类可以变化。
2) 扩展功能的类也可以变化。
通俗讲就是给x增加y功能,x和y都可以动态的设置,灵活性大大的提高了。
这些可变的东西还可以用配置文件来代替,操作将更为灵活。
继承 | 装饰者模式 | 动态代理模式 | |
---|---|---|---|
作用 | 增加功能(给x添加y功能) | 增加功能(给x添加y功能) | 增加功能(给x添加y功能) |
优点 | x可变 | x和y都可变 | |
缺点 | x和y都不可变 | y不可变 | |
灵活性 | 低 | 中 | 高 |