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

一、代理模式

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

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

Java 设计模式(13) —— 代理模式_第1张图片
代理模式

二、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设计模式所有示例代码,持续更新中

你可能感兴趣的:(Java 设计模式(13) —— 代理模式)