java设计模式6——代理模式

2019/04/10 10:10
阅读数 23

<h1>java设计模式6——代理模式</h1> <h2>1、代理模式介绍:</h2> <h3>1.1、为什么要学习代理模式?因为这就是Spring Aop的底层!(SpringAop 和 SpringMvc)</h3> <h3>1.2、代理模式的分类:</h3> <ul> <li>静态代理</li> <li>动态代理</li> </ul> <h3>1.3、代理模式关系图(以租房子为例)</h3> <p><img src="https://img2018.cnblogs.com/blog/1729297/202002/1729297-20200214171754933-913950542.png" /></p> <h2>2、静态代理</h2> <h3>2.1、角色分析:</h3> <ol> <li>抽象角色:一般会使用接口或者抽象类来解决</li> <li>真实角色:被代理的角色</li> <li>代理客户:代理真实角色。代理真实角色后,我们一般会做一些附属的操作</li> <li>客户:访问代理对象的人</li> </ol> <h3>2.2、例1(租房子演示)</h3> <h3>2.2.1、抽象角色实现(房东抽象类)</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;

/**

  • 租房 */ public interface Rent {

    void rent(); } </code></pre>

<h3>2.2.2、真实角色实现(房东的实现类)</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;

/**

  • 房东 */ public class Host implements Rent {

    @Override public void rent() { System.out.println("房东要出租房子!"); } } </code></pre>

<h3>2.2.3、不通过代理进行租房</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;

public class Client { public static void main(String[] args) { //直接找房东 Host host = new Host(); host.rent(); } } </code></pre>

<h3>运行结果:</h3> <pre><code>房东要出租房子! </code></pre>

<h3>2.2.4、弊端</h3> <ol> <li>在实际的生活场景中,房东可能只卖房,而不负责租房</li> <li>如果要提高租房子的成功率,必然还需要一些其他的服务,如:看房、谈价钱、签合同等,而这些房东并不想参与,因此产生了中介,也就是代理。</li> </ol> <h3>2.2.5、代理出现</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;

public class Proxy implements Rent {

private Host host;

public Proxy() {

}

public Proxy(Host host) {
    this.host = host;
}

@Override
public void rent() {
    seeHouse();
    host.rent();
    fare();
    hetong();
}

//看房
public void seeHouse() {
    System.out.println(&quot;中介代理看房&quot;);
}

//收中介费
public void fare() {
    System.out.println(&quot;收中介费&quot;);
}

public void hetong() {
    System.out.println(&quot;签合同&quot;);
}

} </code></pre>

<h3>2.2.6、通过代理来租房子</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;

public class Client { public static void main(String[] args) { /* //直接找房东 Host host = new Host(); host.rent();*/

    //通过代理去租房子
    //房东要租房子
    Host host = new Host();
    //代理
    //中介帮房东租房子,但是,中介一半都会有一些附属操作
    Proxy proxy = new Proxy(host);
    proxy.rent();
}

} </code></pre>

<h3>运行结果:</h3> <pre><code>中介代理看房 房东要出租房子! 收中介费 签合同 </code></pre>

<h3>2.3、分析:</h3> <h3>代理模式的好处</h3> <ol> <li>可以使真实角色的操作更加纯粹,不用去关注一些公共的业务。</li> <li>公共的业务交给了代理角色去完成,实现了业务的分工。</li> <li>公共业务发生扩展的时候,方便集中管理。</li> </ol> <h3>缺点:</h3> <ul> <li>一个真实角色就会产生一个代理的角色,代码量翻倍,开发效率变低。</li> </ul> <h3>2.4、例1(增删改查业务的演示)</h3> <h3>2.4.1、编写service的抽象类</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.静态代理.Demo2;

public interface UserService { void add(); void del(); void update(); void query(); } </code></pre>

<h3>2.4.2、编写service的实现类</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.静态代理.Demo2;

/**

  • 真实对象 */ public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("增加了一个用户"); }

    @Override public void del() { System.out.println("删除了一个用户"); }

    @Override public void update() { System.out.println("更新了一个用户"); }

    @Override public void query() { System.out.println("查询了一个用户"); } } </code></pre>

<h3>2.4.3、如果此时想不改变原有的代码,而增加方法日志打印的功能,此时代理诞生</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.静态代理.Demo2;

/**

  • 代理角色,增加日志的功能 */ public class UserServiceProxy implements UserService {

    private UserService userService;

    public void setUserService(UserService userService) { this.userService = userService; }

    @Override public void add() { userService.add(); log("add"); }

    @Override public void del() { userService.del(); log("del"); }

    @Override public void update() { userService.update(); log("update"); }

    @Override public void query() { userService.query(); log("query"); }

    public void log(String msg) { System.out.println("使用了" + msg + "方法!"); } } </code></pre>

<h3>2.4.4、编写客户端类,使用service的方法,并打印日志</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.静态代理.Demo2;

public class Client { public static void main(String[] args) { UserService userService = new UserServiceImpl();

    UserServiceProxy proxy = new UserServiceProxy();
    proxy.setUserService(userService);

    proxy.add();
    proxy.del();
    proxy.update();
    proxy.query();
}

} </code></pre>

<h3>运行结果:</h3> <pre><code>增加了一个用户 使用了add方法! 删除了一个用户 使用了del方法! 更新了一个用户 使用了update方法! 查询了一个用户 使用了query方法! </code></pre>

<h3>2.5、反思:在实际的业务中,横向开发的好处</h3> <p><img src="https://img2018.cnblogs.com/blog/1729297/202002/1729297-20200214174407164-880395182.png" /></p> <h3>可以保证原有代码的可行性,不会对软件原来的版本进行破坏,向过去兼容。</h3> <h2>3、动态代理</h2> <h3>3.1、动态代理的特点</h3> <ol> <li>动态代理和静态代理一样</li> <li>动态代理的代理类是动态生成的,不是我们直接写的</li> </ol> <h3>3.2、动态代理实现方式的分类</h3> <ul> <li>基于接口——JDK动态代理(本节需要讲述的方式)</li> <li>基于类:cglib</li> <li>java字节码实现:javasist</li> </ul> <h3>3.3、需要了解的两个类</h3> <ul> <li>Proxy:代理类</li> <li>InvocationHandler:调用处理程序类</li> </ul> <h3>具体的使用参照java的api</h3> <h3>3.4、例1——房东租房的例子</h3> <h3>3.4.1、房东的接口和实现类不变</h3> <h3>3.4.2、实现自动生成代理的类</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.动态代理.Demo1;

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;

/**

  • 等下我们会用这个类,自动生成代理类 */ public class ProxyInvocationHandler implements InvocationHandler {

    /**

    • 被代理的接口 */ private Rent rent;

    public void setRent(Rent rent) { this.rent = rent; }

    /**

    • 获得一个代理
    • @return */ public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this); }

    /**

    • 处理代理实例,并放回结果
    • @param proxy
    • @param method
    • @param args
    • @return
    • @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //用反射来执行方法 seeHouse(); //调用代理自身的方法 //动态代理的本质,就是使用反射机制来实现 Object result = method.invoke(rent, args); fare(); hetong(); return result; }

    public void seeHouse() { System.out.println("中介带看房子!"); }

    //收中介费 public void fare() { System.out.println("收中介费"); }

    public void hetong() { System.out.println("签合同"); } } </code></pre>

<h3>3.4.3、实现客户端使用代理来租房子</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.动态代理.Demo1;

public class Client { public static void main(String[] args) { //真实角色 Host host = new Host();

    //代理角色
    ProxyInvocationHandler pih = new ProxyInvocationHandler();
    //通过调用程序处理角色,来处理我们要调用的接口对象
    pih.setRent(host);

    //放回代理类
    //这里的代理类就是动态生成的,我们并没有写他
    Rent proxy = (Rent) pih.getProxy();
    proxy.rent();
}

} </code></pre>

<h3>运行结果:</h3> <pre><code>中介带看房子! 房东要出租房子! 收中介费 签合同 </code></pre>

<h3>3.5、例2——增删改查的例子</h3> <h3>3.5.1、先来实现一个万能的代理生成类</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.动态代理.Demo2;

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;

/**

  • 万能代理类 */ public class ProxyInvocationHandler implements InvocationHandler {

    /**

    • 被代理的接口 */ private Object target;

    public void setTarget(Object target) { this.target = target; }

    /**

    • 获得一个代理
    • @return */ public Object getProxy() { return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this); }

    /**

    • 处理代理实例,并放回结果
    • @param proxy
    • @param method
    • @param args
    • @return
    • @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //用反射来执行方法 //动态代理的本质,就是使用反射机制来实现 Object result = method.invoke(target, args); log(method.getName()); return result; }

    public void log(String msg) { System.out.println("使用了" + msg + "方法!"); } } </code></pre>

<h3>也就是将上一个例子的具体实现类——房东类,替换成Object类</h3> <h3>3.5.2、UserService的接口和实现类不变</h3> <h3>3.5.3、编写客户端类使用代理调用增删改查方法</h3> <pre><code>package com.xgp.company.结构性模式.代理模式.动态代理.Demo2;

public class Client { public static void main(String[] args) { //真实角色 UserService userService = new UserServiceImpl(); //代理角色 ProxyInvocationHandler pih = new ProxyInvocationHandler(); pih.setTarget(userService); UserService proxy = (UserService) pih.getProxy();

    proxy.add();
    proxy.del();
    proxy.update();
    proxy.query();
}

} </code></pre>

<h3>运行结果:</h3> <pre><code>增加了一个用户 使用了add方法! 删除了一个用户 使用了del方法! 更新了一个用户 使用了update方法! 查询了一个用户 使用了query方法! </code></pre>

<h3>3.6、弊端分析:</h3> <h3>虽然使用动态代理能够节省代码量,并且实现静态代理的全部优点。但是,动态代理的核心是反射技术,通过反射技术调用方法效率较大,因此也可能影响系统效率。</h3> <h3>3.7、动态代理的好处</h3> <h3>一个动态代理的是一个接口,一般就是对应的一类业务。</h3>

原文出处:https://www.cnblogs.com/xgp123/p/12308415.html

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部