设计模式之装饰模式和动态代理模式

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!

装饰器模式的应用场景:

  1. 需要扩展一个类的功能

  2. 动态的为一个对象增加功能, 而且还能动态的撤销. (继承不能做到这一点, 继承的功能是静态的, 不能动态增删)

缺点:

产生过多的相似对象, 不易拍错!

反思: 装饰器的本质是什么?

装饰器本身的一个本质, 就是不想改变原来的函数, 但是还想给该函数增加或者删除一些功能.就是装饰器, 和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!

代理模式的应用场景:

如果已有的方法在使用的时候需要对原有的方法进行改进, 此时有两种方法:

  1. 修改原来的方法来适应. 这样违反了"对扩展开放, 对修改关闭"的原则.

  2. 就是采用一个代理类调用原有的方法, 且对生产的结果进行控制, 这种方法就是代理模式

使用代理模式, 可以将功能划分的更加清晰, 有助于后期维护.

装饰和模式和静态代理模式的区别:

静态代理, 更加关注的类, 传入的是这个对象的具体实例

而装饰模式传入的是一个接口, 在调用接口实现的时候, 会调用接口实现里面的方法, 是动态的.

动态代理

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
======插入后者通知======

动态代理的本质:

都不是通过自己时间, 都是通过中间的代理对象, 代理对象调用父类的方法, 还可以在前面和后面增加一些功能

行为型设计模式

模板方法模式

策略模式

其他设计模式

MVC设计模式

委托设计模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值