设计模式-代理模式(Proxy)

  • Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供一种代理以控制对这个对象的访问。)

    代理模式也叫委托模式。许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式,而且在日常的应用中,代理模式可以提供非常好的访问控制。
    一个代理类可以代理多个被委托者或被代理者,因此一个代理类具体代理哪个真实主题
    角色,是由场景类决定的。当然,最简单的情况就是一个主题类和一个代理类,这是最简洁的代理模式。在通常情况下,一个接口只需要一个代理类就可以了,具体代理哪个实现类由高层模块来决定,也就是在代理类的构造函数中传递被代理
先看一个简单的代理模式例子

苹果手机生产就是一个很真实的代理模式,苹果自己不生产手机,它的手机基本都是通过代理公司来生产的。
我们现在模拟生产手机这个场景来让大家对代理模式的初识

生产手机步骤 Phone

/**
 * @author shuliangzhao
 * @Title: Phone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:04
 */
public interface Phone {

    //安装屏幕
    void assemblyScreen();
    //安装电池
    void battery();
    //软件测试
    void software();
}

ApplePhone

/**
 * @author shuliangzhao
 * @Title: ApplePhone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:07
 */
public class ApplePhone implements Phone {

    @Override
    public void assemblyScreen() {
        System.out.println("安装屏幕!");
    }

    @Override
    public void battery() {
        System.out.println("安装电池!");
    }

    @Override
    public void software() {
        System.out.println("调试软件!");
    }
}

代理类PorxyPhoneFactory

/**
 * @author shuliangzhao
 * @Title: PorxyPhoneFactory
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:15
 */
public class PorxyPhoneFactory implements Phone {

    private Phone phone = null;

    public PorxyPhoneFactory(Phone phone) {
        this.phone = phone;
    }

    @Override
    public void assemblyScreen() {
        this.phone.assemblyScreen();
    }

    @Override
    public void battery() {
        this.phone.battery();
    }

    @Override
    public void software() {
        this.phone.software();
    }
}

客户端

/**
 * @author shuliangzhao
 * @Title: Client
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:16
 */
public class Client {

    public static void main(String[] args) {
        Phone phone = new ApplePhone();
        Phone proxyPhone = new PorxyPhoneFactory(phone);
        proxyPhone.assemblyScreen();
        proxyPhone.battery();
        proxyPhone.software();
    }
}

运行结果


image.png
代理模式一般分为普通代理、强制代理、动态代理

1.普通代理

普通代理就是我们要知道代理的存在,也就是类似的PorxyPhoneFactory 这个类的存在,然后才能访问。普通代理只能访问代理角色,而不能访问真实角色,苹果不能自己生产手机,场景类不能直接new ApplePhone,,它必须由PorxyPhoneFactory来进行
模拟场景。
Phone

/**
 * @author shuliangzhao
 * @Title: Phone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:04
 */
public interface Phone {

    //安装屏幕
    void assemblyScreen();
    //安装电池
    void battery();
    //软件测试
    void software();
}

OrdianyApplePhone

/**
 * @author shuliangzhao
 * @Title: ApplePhone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:28
 */
public class OrdianyApplePhone implements Phone {

    private String name = "";

    public OrdianyApplePhone(Phone phone, String name) throws Exception {
        if (phone == null) {
            throw new Exception("不能生产手机");
        }else {
            this.name = name;
        }
    }

    @Override
    public void assemblyScreen() {
        System.out.println(this.name + "组装屏幕");
    }

    @Override
    public void battery() {
        System.out.println(this.name + "组装电池");
    }

    @Override
    public void software() {
        System.out.println(this.name + "调试软件");
    }
}

OrdianyProxyPhoneFactory

/**
 * @author shuliangzhao
 * @Title: OrdianyProxyPhoneFactory
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:33
 */
public class OrdianyProxyPhoneFactory implements Phone {

    private Phone phone = null;

    public OrdianyProxyPhoneFactory(String name) {
        try {
            phone = new OrdianyApplePhone(this,name);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void assemblyScreen() {
        phone.assemblyScreen();
    }

    @Override
    public void battery() {
        phone.battery();
    }

    @Override
    public void software() {
        phone.software();
    }
}

客户端 Client

/**
 * @author shuliangzhao
 * @Title: Client
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:36
 */
public class Client {

    public static void main(String[] args) {
        Phone phone = new OrdianyProxyPhoneFactory("富士康");
        phone.assemblyScreen();
        phone.battery();
        phone.software();
    }
}

运行结果


image.png

仅仅修改了构造函数,传递进来一个代理者名称,即可进行代理,在这种改造下,系统
更加简洁了,调用者只知道代理存在就可以,不用知道代理了谁。

2.强制代理

强制代理比较另类,一般思维都是通过代理找真实类,但是强制代理是通过真实角色找代理类,否则你不能访问。这好比你给你老板打电话,你老板说我很忙,你先找下我的秘书。本来你想绕过秘书找老板,但是返回的还是秘书,这就是强制代理。
ForcePhone

/**
 * @author shuliangzhao
 * @Title: ForcePhone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:50
 */
public interface ForcePhone {
    //安装屏幕
    void assemblyScreen();
    //安装电池
    void battery();
    //软件测试
    void software();
    //每个工厂都可以找自己代理
    ForcePhone getPorxy();
}

ForceApplePhone

public class ForceApplePhone implements ForcePhone{

    private String name = "";

    private ForcePhone forcePhone = null;

    public ForceApplePhone(String name) {
        this.name = name;
    }

    @Override
    public void assemblyScreen() {
        if (this.isProxy()) {
            System.out.println(name + "组装电脑");
        }else {
            System.out.println("请使用代理指定服务!");
        }
    }

    @Override
    public void battery() {
        if (this.isProxy()) {
            System.out.println(name + "组装电池");
        }else {
            System.out.println("请使用代理指定服务!");
        }
    }

    @Override
    public void software() {
        if (this.isProxy()) {
            System.out.println(name + "调试软件");
        }else {
            System.out.println("请使用代理指定服务!");
        }
    }

    //找到自己代理
    @Override
    public ForcePhone getPorxy() {
        this.forcePhone = new ForceProxyPhoneFactory(this);
        return this;
    }

    //增加了一个私有方法,检查是否是自己指定的代理,是指定的代理则允许访问,否则不
    //允许访问。
    private boolean isProxy(){
        if(this.forcePhone == null){
            return false;
        }else{
            return true;
        }
    }
}

ForceProxyPhoneFactory

public class ForceProxyPhoneFactory implements ForcePhone {

    private ForcePhone forcePhone;
    public ForceProxyPhoneFactory(ForcePhone forcePhone) {
        this.forcePhone = forcePhone;
    }

    @Override
    public void assemblyScreen() {
        forcePhone.assemblyScreen();
    }

    @Override
    public void battery() {
        forcePhone.battery();
    }

    @Override
    public void software() {
        forcePhone.software();
    }

    @Override
    public ForcePhone getPorxy() {
        return this;
    }
}

客户端 Client

/**
 * @author shuliangzhao
 * @Title: Client
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:58
 */
public class Client {

    public static void main(String[] args) {
        //场景一
        System.out.println("=================场景一=============");
        ForcePhone forcePhone = new ForceApplePhone("富士康");
        ForcePhone proxyForcePhone = new ForceProxyPhoneFactory(forcePhone);
        proxyForcePhone.assemblyScreen();
        proxyForcePhone.battery();
        proxyForcePhone.software();
        System.out.println("++++++++++++++++++++++++++++++++++");
        //场景二
        System.out.println("=================场景二=============");
        ForcePhone forcePhone1 = new ForceApplePhone("富士康");
        forcePhone1.assemblyScreen();
        forcePhone1.battery();
        forcePhone1.software();
        System.out.println("+++++++++++++++++++++++++++++++++++");
        //场景三
        System.out.println("=================场景三=============");
        ForcePhone forcePhone2 = new ForceApplePhone("富士康");
        ForcePhone porxy = forcePhone2.getPorxy();
        porxy.assemblyScreen();
        porxy.battery();
        porxy.software();
    }
}
image.png

总结:
场景一出现原因:不能访问原因,你new自己出来当然真实对象不认,就好比老板已经告诉你了去找秘书,你不能随便找一个秘书啊!
场景二出现原因:你必须通过代理来访问,直接访问不行。

2.动态代理

动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。AOP的核心机制就是动态代理。主要实现jdk中的InvocationHandler接口
DynamicPhone

/**
 * @author shuliangzhao
 * @Title: Phone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:04
 */
public interface DynamicPhone {

    //安装屏幕
    void assemblyScreen();
    //安装电池
    void battery();
    //软件测试
    void software();
}

DynamicApplePhone

/**
 * @author shuliangzhao
 * @Title: ApplePhone
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/30 23:07
 */
public class DynamicApplePhone implements DynamicPhone {

    private String name;
    public DynamicApplePhone(String name) {
        this.name = name;
    }

    @Override
    public void assemblyScreen() {
        System.out.println(name+"安装屏幕!");
    }

    @Override
    public void battery() {
        System.out.println(name+"安装电池!");
    }

    @Override
    public void software() {
        System.out.println(name+"调试软件!");
    }
}

PhoneHandler

/**
 * @author shuliangzhao
 * @Title: PhoneHandler
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/31 0:13
 */
public class PhoneHandler implements InvocationHandler {

    //被代理的实例
    private Object obj = null;
    //我要代理谁
    public PhoneHandler(Object obj){
        this.obj = obj;
    }

    //调用被代理的方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(this.obj, args);
        //return invoke;
    }
}

客户端

/**
 * @author shuliangzhao
 * @Title: Client
 * @ProjectName design-parent
 * @Description: TODO
 * @date 2019/5/31 0:16
 */
public class Client {
    public static void main(String[] args) {
        DynamicPhone dynamicPhone = new DynamicApplePhone("富士康");
        InvocationHandler phoneHandler = new PhoneHandler(dynamicPhone);
        ClassLoader classLoader = dynamicPhone.getClass().getClassLoader();
        DynamicPhone o = (DynamicPhone) Proxy.newProxyInstance(classLoader, dynamicPhone.getClass().getInterfaces(), phoneHandler);
        o.assemblyScreen();
        o.battery();
        o.software();
    }
}

运行结果


image.png

代理模式的优点

1.职责清晰
2.扩展和智能

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

推荐阅读更多精彩内容