Java 设计模式(13) —— 代理模式

一、代理模式

为一个对象提供一个替身,以控制对这个对象的访问。

被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象代理模式有很多变体,都是为了控制与管理对象访问

代理模式

二、RMI示例

上篇博文状态模式中的示例糖果机项目,现在如果要改进远程控制的糖果机,则本地程序无需修改,只需新增远程代理控制即可。就可使用RMI远程通讯。

  • RMI远程方法调用是计算机之间通过网络实现对象调用的一种通讯机制。 使用这种机制,一台计算机上的对象可以调用另外 一台计算机上的对象来获取远 程数据。

  • 在过去,TCP/IP通讯是远程通讯的主要手段,面向过程的开发。 而RPC使程序员更容易地调用远程程序,但在面对复杂的信息传讯时,RPC依然 未能很好的支持

  • RMI被设计成一种面向对象开发方式,允许程序员使用远程对象来实现通信

  • RMId的实现步骤

    • 1.制作远程接口:接口文件
    • 2.远程接口的实现:Service文件
    • 3.RMI服务端注册,开启服务
    • 4.RMI代理端通过RMI查询到服务端,建立联系,通过接口调用远程方法
  • RMI 简单的代码示例

1.定义接口远程调用的接口方法

/**
 * 定义服务的接口,继承RMI的远程协议
 */
public interface MyRemote extends Remote{

    public String sayHello() throws RemoteException;
    
}

2.RMI服务端


/**
 * RMI服务端,实现接口方法,提供服务
 */
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {

    protected MyRemoteImpl() throws RemoteException {
        super();
    }

    @Override
    public String sayHello() throws RemoteException {
        return "Hello World!";
    }

    public static void main(String[] args) {

        try {
            MyRemote service = new MyRemoteImpl();
            // LocateRegistry.createRegistry(6600);
            Naming.rebind("rmi://101.232.197.163:6600/RemoteHello", service);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.toString());
        }


    }
}

3.RMI客户端


/**
 * RMI客户端,远程连接服务端,调用远程服务
 */
public class MyRemoteClient {
    public static void main(String[] args) {

        new MyRemoteClient().go();
    }

    public void go() {
        try {
            MyRemote service = (MyRemote) Naming.lookup("rmi://127.0.0.1:6600/RemoteHello");
            String s = service.sayHello();
            System.out.println(s);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

以上是简单的RMI调用方法示例,可以尝试用来改进之前状态模式的糖果机项目为远程控制的糖果机

三、几种常见的代理模式

  • 虚拟代理:为创建开销大的对象提供代理服务,真正的对象在创建前和创建中时,由虚拟代理来扮演替身

  • 动态代理:运行时动态的创建代理类,并将方法调用转发到指定类

  • 保护代理:对象的保护,属性的保护

  • 防火墙代理:类似互联网的防火墙

  • 缓存代理:例如访问图片或者访问网页的本地缓存

  • 智能引用代理:访问对象时,增加一些辅助的功能

  • 同步代理:多线程之间的对象同步

  • 写入时复制代理:copy函数

一个动态代理和保护代理的示例:人物的打分,自己只能看自己的分数或者给别人打分


/**
 * 定义代理的接口方法
 */
public interface PersonBean {
    String getName();
    String getGender();
    String getInterests();
    int getHotOrNotRating();
    
    void setName(String name);
    void setGender(String gender);
    void setInterests(String interests);
    void setHotOrNotRating(int rating);
}


/**
 * 代理接口的方法实现
 */
public class PersonBeanImpl implements PersonBean {
    String name;
    String gender;
    String interests;
    int rating;
    int ratingcount = 0;

    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getGender() {
        return gender;
    }

    @Override
    public String getInterests() {
        return interests;
    }

    @Override
    public int getHotOrNotRating() {
        if (ratingcount == 0) return 0;
        return (rating / ratingcount);
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public void setInterests(String interests) {
        this.interests = interests;
    }

    @Override
    public void setHotOrNotRating(int rating) {
        this.rating = rating;
        ratingcount++;
    }

}


/**
 * 动态代理,保护代理,不是本人的属性提供代理方法
 */
public class NonOwnerInvocationHandler implements InvocationHandler {
    PersonBean person;

    public NonOwnerInvocationHandler(PersonBean person) {
        this.person = person;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

        if (method.getName().startsWith("get")) {
            return method.invoke(person, args);
        } else if (method.getName().equals("setHotOrNotRating")) {
            return method.invoke(person, args);

        } else if (method.getName().startsWith("set")) {
            return new IllegalAccessException();
        }

        return null;
    }

}


/**
 * 动态代理,保护代理,自己允许调用的方法提供代理
 */
public class OwnerInvocationHandler implements InvocationHandler {
    PersonBean person;

    public OwnerInvocationHandler(PersonBean person) {
        this.person = person;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

        if (method.getName().startsWith("get")) {
            return method.invoke(person, args);
        } else if (method.getName().equals("setHotOrNotRating")) {
            return new IllegalAccessException();
        } else if (method.getName().startsWith("set")) {
            return method.invoke(person, args);
        }

        return null;
    }

}

四、总结

  • 代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
  • 代理模式的思想是为了提供额外的处理或者不同的操作而在实际对象与调用者之间插入一个代理对象。这些额外的操作通常需要与实际对象进行通信。


Java设计模式所有示例代码,持续更新中

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容