8. 装饰模式
顾名思义, 装饰模式就是给一个对象增加装饰一些新的功能, 而且是动态的, 要求装饰对象和被装饰对象实现同一个接口, 装饰对象持有被装饰对象的实例
Source类是被装饰类, Decorator类是一个装饰类, 可以为Source类动态的增加一些功能, 代码如下:
public interface Sourceable {
public void method();
}
public class Source implements Sourceable {
@Override
public void method() {
System.out.println("the original method!")
}
}
public class Decorator implements sourceable {
private Sourceable source;
private Decorator(Sourceable source) {
super();
this.source = source;
}
@Override
public void method() {
System.out.println("before decorator!");
source.method();
System.out.println("after decorator!");
}
}
测试类:
before decorator!
the original method!
after decorator!
装饰器模式的应用场景:
- 需要扩展一个类的功能
- 动态的为一个对象增加功能, 而且还能动态的撤销. (继承不能做到这一点, 继承的功能是静态的, 不能动态增删)
缺点:
产生过多的相似对象, 不易拍错!
反思: 装饰器的本质是什么?
装饰器本身的一个本质, 就是不想改变原来的函数, 但是还想给该函数增加或者删除一些功能.就是装饰器, 和python的也很类似, 装饰器就是适配器思想的一种实现
装饰模式是针对接口的
9. 代理模式(面试)
其实每个模式名称就表明了改模式的作用, 代理模式就是多一个代理类出来, 替原对象进行一些操作, 代理又分为动态代理和静态代理
静态代理
比如我们在租房子的时候去找中介, 为什么呢?因为你对该地区房屋信息掌握的不够全面, 希望找一个更熟悉的人去帮你做, 此处的代理就是这个意思. 代码如下:
public interface Sourceable {
public void method();
}
public class Source implements Sourceable {
@Override
public void method() {
System.out.println("the original method!");
}
}
public class Proxy implements Sourceable {
private Source source;
public Proxy() {
super();
this.source = new Source;
}
@Override
public void method() {
before();
source.method();
after();;
}
private void before() {
system.out.println("before proxy!");
}
private void after() {
system.out.println("after proxy!");
}
}
测试类:
public class ProxyTest {
public static void main(String[] args) {
Sourceable source = new Proxy();
source.method();
}
}
输出:
before proxy!
the original method!
after proxy!
代理模式的应用场景:
如果已有的方法在使用的时候需要对原有的方法进行改进, 此时有两种方法:
- 修改原来的方法来适应. 这样违反了"对扩展开放, 对修改关闭"的原则.
- 就是采用一个代理类调用原有的方法, 且对生产的结果进行控制, 这种方法就是代理模式
使用代理模式, 可以将功能划分的更加清晰, 有助于后期维护.
装饰和模式和静态代理模式的区别:
静态代理, 更加关注的类, 传入的是这个对象的具体实例
而装饰模式传入的是一个接口, 在调用接口实现的时候, 会调用接口实现里面的方法, 是动态的.
动态代理
JDK动态代理
package com.lnjecit.proxy;
/**
* Subject
* 抽象主题接口
* @author
* @create 2018-03-29 14:16
**/
public interface Subject {
void doSomething();
}
/**
* RealSubject
* 真实主题类
* @author
* @create 2018-03-29 14:21
**/
public class RealSubject implements Subject {
@Override
public void doSomething() {
System.out.println("RealSubject do something");
}
}
基于接口去实现的动态代理
package com.lnjecit.proxy.dynamic.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDKDynamicProxy
* jdkd动态代理
*
* @author
* @create 2018-03-29 16:17
**/
public class JDKDynamicProxy implements InvocationHandler {
private Object target;
public JDKDynamicProxy(Object target) {
this.target = target;
}
/**
* 获取被代理接口实例对象
* @param <T>
* @return
*/
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Do something before");
Object result = method.invoke(target, args);
System.out.println("Do something after");
return result;
}
}
测试类:
package com.lnjecit.proxy;
import com.lnjecit.proxy.dynamic.jdk.JDKDynamicProxy;
/**
* Client
* client测试代码
*
* @author
* @create 2018-03-29 14:26
**/
public class Client {
public static void main(String[] args) {
// 保存生成的代理类的字节码文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// jdk动态代理测试
Subject subject = new JDKDynamicProxy(new RealSubject()).getProxy();
subject.doSomething();
}
}
输出结果:
Do something before
RealSubject do something
Do something after
CGLib动态搭理
实现一个业务类,注意,这个业务类并没有实现任何接口:
package com.jpeony.spring.proxy.cglib;
public class HelloService {
public HelloService() {
System.out.println("HelloService构造");
}
/**
* 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
*/
final public String sayOthers(String name) {
System.out.println("HelloService:sayOthers>>"+name);
return null;
}
public void sayHello() {
System.out.println("HelloService:sayHello");
}
}
自定义MethodInterceptor:
package com.jpeony.spring.proxy.cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 自定义MethodInterceptor
*/
public class MyMethodInterceptor implements MethodInterceptor{
/**
* sub:cglib生成的代理对象
* method:被代理对象方法
* objects:方法入参
* methodProxy: 代理方法
*/
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("======插入后者通知======");
return object;
}
}
生成CGLIB代理对象调用目标方法:
package com.jpeony.spring.proxy.cglib;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
public class Client {
public static void main(String[] args) {
// 代理类class文件存入本地磁盘方便我们反编译查看源码
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\code");
// 通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(HelloService.class);
// 设置enhancer的回调对象
enhancer.setCallback(new MyMethodInterceptor());
// 创建代理对象
HelloService proxy= (HelloService)enhancer.create();
// 通过代理对象调用目标方法
proxy.sayHello();
}
}
输出:
HelloService构造
======插入前置通知======
HelloService:sayHell
======插入后者通知======
动态代理的本质:
都不是通过自己时间, 都是通过中间的代理对象, 代理对象调用父类的方法, 还可以在前面和后面增加一些功能