代理模式

是什么?

代理模式为某对象创建一个代理对象,让代理对象控制该对象的访问。被代理对象可以使远程的对象、创建开销大的对象或需要安全控制的对象。

结构组成及作用

下图是代理模式的UML类图:  Proxy Pattern UML Class diagram

作用

《head first Design Patterns》和 Gang of Four的《设计模式》 [1] 两本书中,都描述了三种代理形式:远程代理、虚拟代理、保护代理。 从这三种代理可窥探出代理模式的作用:

  1. 提供一种不同空间的局部代理。
  2. 根据需要创建开销大的对象。
  3. 控制对ConcreteSubject对象(如图,即被代理对象)的访问。

其实这三种形式的类图结构都有所不同,事实上,是存在很多代理模式的变体的,但是,其实我们要记得的是他们行为的共通点是: 将客户(Caller)对ConcreteSubject对象(如图,即被代理对象)的直接访问拦截下来,变为间接。那么这个行为将提供给我们在其中很大的操作空间。

示例实现

下面我将提供 远程代理、虚拟代理、保护代理三种形式的实现。

虚拟代理

觉得《head first设计模式》的例子挺好,本来想试着用javaFx模拟实现一下,后来做了下发现javaFx的Image加载图片时是不会假死,所以就照这书里的swing实现做了一次。

代码不贴了,贴两个效果图,可以看到通过代理模式,图片实现延迟及异步加载了。

 output1  output2

完整代码么么哒

保护代理

保护代理有两种:一种是按照上面类图实现的静态代理,一种是我们喜闻乐见的Java提供Proxy API的作为Spring AOP原理的动态代理。

下面模拟一般业务后端给DAO或Service的代理。

公用类

User类及其Builder

public class User {
    private String id;
    private String name;
    private String description;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}
public class UserBuilder {

    private String id;
    private String name;
    private String description;

    public static UserBuilder create() {
        return new UserBuilder();
    }


    public UserBuilder id(String id) {
        this.id = id;
        return this;
    }


    public UserBuilder name(String name) {
        this.name = name;
        return this;
    }


    public UserBuilder description(String description) {
        this.description = description;
        return this;
    }

    public UserBuilder defaultValue() {
        id = "default";
        name = "default_name";
        description = "default_description";
        return this;
    }

    public User build() {
        User user = new User();
        user.setId(id);
        user.setName(name);
        user.setDescription(description);
        return user;
    }
}

DAO实现类

public class UserDAOImpl implements UserDAO {
    @Override
    public void save(User user) {
        System.out.println("user saved!!");
    }

    @Override
    public void delete() {
        System.out.println("user deleted!!!");
    }
}
静态代理
import com.tea.proxy.protectProxy.User;
import com.tea.proxy.protectProxy.UserDAO;

public class ProtectProxy implements UserDAO {
    private UserDAO userDAO;

    public ProtectProxy(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    @Override
    public void save(User user) {
        System.out.println("before saving user!some Operation!");
        userDAO.save(user);
    }

    @Override
    public void delete() {
        System.out.println("before deletion!some Operation!");
        userDAO.delete();
    }
}
import com.tea.proxy.protectProxy.User;
import com.tea.proxy.protectProxy.UserBuilder;
import com.tea.proxy.protectProxy.UserDAO;
import com.tea.proxy.protectProxy.UserDAOImpl;

public class TestMain {
    public static void main(String[] args) {
        UserDAO userDAO = new UserDAOImpl();
        UserDAO userDAOProxy = new ProtectProxy(userDAO);
        User user = UserBuilder.create().defaultValue().build();

        userDAOProxy.save(user);
        userDAOProxy.delete();
    }
}
动态代理
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class ProtectedProxy implements InvocationHandler {

    private Object target;

    public Object getTarget() {
        return target;
    }

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

    public void beforeMethod(Method m) {

        System.out.println(m.getName() + " start");
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        beforeMethod(method);//对特定方法做一些类似事务,验证等的操作
        method.invoke(target, args);
        return null;
    }
}
import com.tea.proxy.protectProxy.User;
import com.tea.proxy.protectProxy.UserBuilder;
import com.tea.proxy.protectProxy.UserDAO;
import com.tea.proxy.protectProxy.UserDAOImpl;

import java.lang.reflect.Proxy;

public class TestMain {
    public static void main(String[] args) {
        UserDAO userDAO = new UserDAOImpl();
        ProtectedProxy pp = new ProtectedProxy();
        pp.setTarget(userDAO);

        UserDAO userDAOProxy = (UserDAO) Proxy.newProxyInstance(userDAO.getClass().getClassLoader(), userDAO.getClass().getInterfaces(), pp);

        User user = UserBuilder.create().build();
        userDAOProxy.save(user);
        userDAOProxy.delete();
    }
}

完整代码么么哒

远程代理

把远程代理放到这几个代理之后是因为远程代理还有我没能解决的rmi的报错问题。放在这里希望有熟悉rmi的有缘人帮下忙。

我在github的remoteProxy目录里分别放了三个demo:

  1. 深入浅出设计模式里的demo
  2. 一个小demo
  3. oracle java文档 rmi getting Started的helloworld demo, oracle doc|Getting Started Using Java RMI

翻了不少资料,也debug了好几个最后几个demo基本都卡在了这个exception(stackoverflow 问题 | java.rmi.ConnectException: Connection refused to host: 127.0.1.1; )上,但是问题下的解答并不能解决我的问题。我在网上也发了问题,望有人能解答。

完整代码么么哒

效果及应用场景

作用中的说明。

references

[1] Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides.设计模式:可复用面向对象软件的基础[M].中国:机械工业出版社,2000

results matching ""

    No results matching ""