设计模式-代理模式

  • 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.扩展和智能

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

境里婆娑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值