乐趣区

关于设计模式:Head-First-设计模式-13-代理-Proxy-模式

思考题

如何设计一个反对近程办法调用的零碎?你要怎样才能让开发人员不必写太多代码?让近程调用看起来像本地调用一样,毫无瑕疵?P435

  • 曾经接触过 RPC 了,所以就很容易晓得具体流程:客户端调用指标类的代理对象(消费者)的办法,消费者外部将相干调用信息通过网络传到服务端对应的指标类的代理对象(生产者)中,生产者解析调用信息,而后真正去调用指标类的理论对象,并将返回后果回传给消费者,消费者再返回给客户端。RPC 框架应用代理模式使得外部一系列解决及信息传输等对客户端和服务端是通明的,客户端会认为理论是本地调用一样,不晓得调用了近程办法;服务端也不晓得是在给近程对象提供服务。

思考题

近程调用程序应该齐全通明吗?这是个好主见吗?这个办法可能会产生什么问题?P435

  • 近程调用程序不应该齐全通明。因为引入了网络通信和数据处理(序列化、反序列化和压缩等),可能在相干过程会异样,客户端应该通晓并解决这些异样,而不应该让 RPC 框架消化掉这些异样而返回一些默认值。

代理模式

为另一个对象提供一个替身或占位符以管制对这个对象的拜访。P460

特点

  • 代理管制拜访

    • 近程代理 :管制拜访近程对象 P460
    • 虚构代理 :管制拜访创立开销大的资源 P460
    • 爱护代理 :基于权限管制对资源的拜访 P460
    • 动静代理 :在运行时动静地创立一个代理类,并将办法的调用转发到指定的类 P474
    • 防火墙代理 :管制网络资源的拜访,爱护主题免于“坏客户”的侵害。多用于防火墙零碎 P488
    • 智能援用代理 :当主题被援用时,进行额定的动作,例如计一个对象被援用的次数。可用于对某些操作的日志记录 P488
    • 缓存代理 :为开销大的运算后果提供临时存储;也容许多个客户共享后果,以缩小计算或网络提早。多用于 Web 服务器代理,以及内容治理与出版零碎 P488
    • 同步代理 :在多线程的状况下为主题提供平安的拜访。可用于 JavaSpaces,为分散式环境内的潜在对象汇合提供同步访问控制 P489
    • 简单暗藏代理 :用来暗藏一个类的简单汇合的复杂度,并进行访问控制;有时候也成为外观代理,但与外观模式不同,因为代理管制拜访,而外观模式只提供另一组接口 P489
    • 写入时复制代理 :用来管制对象的复制,办法是提早对象的复制,直到客户真的须要为止。这是虚构代理的变体。CopyOnWriteArrayList 应用这种形式 P489

毛病

  • 代理会造成设计中类的数目减少 P491

代理模式和装璜器模式 P471

  • 代理模式管制对象的拜访
  • 装璜器模式为对象减少行为

代理模式和适配器模式的区别 P471

  • 代理模式实现雷同的接口(爱护代理可能只提供给客户局部接口,与某些适配器很像)
  • 适配器模式扭转对象适配的接口

思考题

class ImageProxy implements Icon {
    // 实例变量结构器在这里
    public int getIconWidth() {if (imageIcon != null) {return imageIcon.getIconWidth();
        } else {return 800;}
    }
    
    public int getIconHeight() {if (imageIcon != null) {return imageIcon.getIconHeight();
        } else {return 600;}
    }
    
    public void paintIcon(final Component c, Graphics g, int y, int y) {if (imageIcon != null) {imageIcon.paintIcon(c, g, x, y);
        } else {g.drawString("Loading CD cover, please wait...", x + 300, y + 190);
            // 实例化 imageIcon 获取图片
        }
    }
}

以上为 CD 封面虚构代理,ImageProxy 类仿佛有两个,由条件语句管制的状态。你是否用另一个设计模式清理这样的代码?你要如何从新设计 ImageProxyP468

  • 能够用状态模式清理掉条件语句。设置两个状态 ImageNotLoadedImageLoaded,别离将各个办法内条件语句内的代码放入这个两个状态的对应办法中,初始状态是 ImageNotLoaded,当第一次调用 paintIcon 办法时,开始实例化 imageIcon 获取图片,胜利后设置状态为 ImageLoaded

思考题

NonOwnerInvocationHandler 工作的形式除了它容许调用 setHotOrNotRating() 和不容许调用其余 set 办法之外,与 NonOwnerInvocationHandler 是很类似的。请写出 NonOwnerInvocationHandler 的代码:P482

import java.lang.reflect.*;

public class NonOwnerInvocationHandler implements InvocationHandler {
    PersonBean person;
    
    public NonOwnerInvocationHandler(PersonBean person) {this.person = person;}
    
    public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException {
        try {String methodName = method.getName();
            if (methodName.startsWith("get")) {return method.invoke(person, args);
            } else if(methodName.equals("setHotOrNotRating")) {return method.invoke(person, args);
            } else if(methodName.startsWith("set")) {throw new IllegalAccessException();
            }
        } catch (IllegalAccessException e) {e.printStackTrace();
        }
        return null;
    }
}

思考题

创立动静代理所须要的代码很短,请你写下 getNonOwnerProxy(),该办法会返回 NonOwnerInvocationHandler 的代理。更进一步,请写下 getProxy() 办法,参数是 handlerperson,返回值是应用此 handler 的代理。P483

PersonBean getNonOwnerProxy(PersonBean person) {return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), new NonOwnerInvocationHandler(person));
}

PersonBean getProxy(InvocationHandler handler, PersonBean person) {return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(), person.getClass().getInterfaces(), handler);
}

思考题

如何晓得某个类是不是代理类?P486

  • JDK 动静代理的类是 Proxy 的子类,有一个静态方法 isProxyClass(),此办法的返回值如果为 true,示意这是一个动静代理类。
  • 【存疑】 代理类还会实现特定的某些接口

    • 在 Java8 中调用 proxy.getClass().getInterfaces() 及其他与获取接口无关的办法,并未发现实现新接口

思考题

能传入 newProxyInstance() 的接口类型,有没有什么限度?

  • 传入的接口数组内只能有接口,不能有类 P486
  • 如果接口不是 public,就必须属于同一个 package P486
  • 【存疑】 不同的接口内,不能够有名称和参数齐全一样的办法 P486

    • 通过 Java8 中实际确认没有此限度,不过永远只会辨认为其中一个接口(接口数组内第一次呈现该办法的接口)的办法
  • 接口数组内的接口能够不是被代理类实现的接口,代理类实现了接口数组内的所有接口,所有接口的调用都能够被拦挡解决
  • 被代理类能够不实现任何接口,本人指定接口和相干调用解决逻辑也能应用

思考题

配对下列模式和形容:P487

代理模式 :包装另一个对象,并管制对它的拜访

外观模式 :包装许多对象以简化它们的接口

装璜器模式 :包装另一个对象,并提供额定的行为

适配器模式 :包装另一个对象,并提供不同的接口

所思所想

  • 以前也看过不同动静代理的实现,但只是蜻蜓点水式地看一遍如何实现,没有理论去入手,这次读书时理论入手后感觉了解更深刻了一点,大略更能理解外部是如何流转的
  • 实际是测验真谛的唯一标准。书中存在局部阐明可能谬误或者不适用于以后版本,要利用好身边的工具,多实际操作,不能尽信书

本文首发于公众号:满赋诸机(点击查看原文)开源在 GitHub:reading-notes/head-first-design-patterns

退出移动版