用心理解设计模式——代理模式 (Proxy Pattern)

前置文章: 设计模式的原则 

其他设计模式:用心理解设计模式专栏

设计模式相关代码已统一放至 我的 Github

 

一、定义

  结构型模式之一。

  Provide a surrogate or placeholder for another object to control acess to ot.

(为其他对象提供一种代理,以控制对这个对象的访问)

二、结构解析

  代理模式的一般结构有三种角色:抽象主题、真实主题(被代理者)、代理者。

  抽象主题:负责定义真实主题要被代理的业务方法接口。

  真实主题:继承抽象主题,实现自己真实的业务方法接口。

  代理者:也继承抽象主题,拥有与真实主题(被代理者)相同的要被代理的业务方法接口, 从外观上看代理者与被代理者似乎一样。代理者内部依赖真实主题,在实现抽象主题定义的接口时,增加了一些前置的访问条件,满足条件后原封不动调用真实主题(被代理者)的业务方法。

三、评价

  代理模式封装了客户访问真实主题(被代理者)的过程,充当代理作用,保护了真实主题(控制了客户对真实主题内容的访问权限)。由于代理者与真实主题接口相同,客户在访问时,并不知道直接访问的是谁,不知道代理者是否存在。

  注意,不要理解跑偏,代理模式的主要作用是访问控制。需要一条龙打杂服务的,请找 外观模式

  事实上,单层的 装饰器模式 (多层可以对装饰进行排列组合)和代理模式难以区分。都可用于增强真实主题的方法。

  代理模式中,各角色的职责清晰,符合开闭原则, 易扩展易复用。

  代理模式也是 AOP(面向切面编程)的重要实现方式之一。

  AOP简单解释:动态地为类的方法(切面上)添加额外的增强逻辑。这些增强逻辑一般与主要功能无关,如日志记录,事件统计、权限验证,异常拦截等。

  使用时,可根据需求,抽取主题类的部分方法为抽象接口,然后对这些接口进行代理(后期代理需求)。

四、实现

namespace Proxy
{
    //抽象主题
    public abstract class Subject
    {
        //定义和声明真实主题要被代理的业务方法接口
        public abstract void DoSth();
    }

    //真实主题
    public class RealSubject : Subject
    {
        //实现业务方法接口,真实要做的事情。
        public override void DoSth(){}
    }

    //代理者
    public class Proxy : Subject
    {
        //内部依赖真实主题
        private Subject subject = new RealSubject();

        //代理者拥有与真实主题(被代理者)
        public override void DoSth()
        {
            //此处定义可访问条件,如只有亲友可访问
            string who = "zhangsan";
            bool canVisit = (who == "kinsfolk" || who == "friend");
            if (canVisit)
            {
                //最终调用真实主题的业务方法
                this.subject.DoSth();
            }
        }
        
        //还可在真实调用前后添加增强逻辑
        private void Before() { }
        private void After() { }
    }

    public class Client
    {
        static public void Main()
        {
            Proxy proxy = new Proxy();
            proxy.DoSth();
        }
    }
}

五、动态代理

  所谓动态代理,即,在运行时为目标接口动态地生成其代理类。(注意是目标接口/不是目标类,这样客户才能无法区分具体调用的是谁。)

  我们已经知道,代理模式可以在接口不变、并且不修改原主题类的情况下,对主题的方法添加访问控制逻辑(或方法增强逻辑)。当有大量的代理需求出现时,就要静态地定义很多代理类。

  动态生成代理,可以统一地对各代理类进行管理,减少冗余的代码。

  在C#中,可以使用 System.Reflection.Emit 动态生成代码。然而在Unity中无法跨平台使用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

NRatel

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

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

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

打赏作者

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

抵扣说明:

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

余额充值