代理模式

来源:互联网 发布:淘宝卖家发布宝贝教程 编辑:程序博客网 时间:2024/04/24 22:46

代理模式

前言

 

今天回到了家,家里两个老的看见我挺开心,我也挺开心啊,一个多月没见我爸妈了,真心挺思念他们,哈哈,闲话不说,开始今天的内容,以前的我们学校食堂离我们很远,宿舍老王所以经常叫外卖,但是我们都告诉他外卖不卫生,还贵啥的,老王就在我们一句一句的诱惑下,终于忍不住了决定不管再远也要找时间去尝尝,但是因为不方便,就委托我们宿舍老李同志帮忙第二天去帮忙充卡,热心肠的老子当然不会拒绝.

 

 

 

模拟场景
 

有了这个前奏,今天的主题当然又有了,那么首先我们用代码来实现上面的功能,首先来分析一下上面的场景:

 

1.我们需要对卡片充值,所以需要一个卡片类,代码如下:

  

  /// <summary>    /// 卡片类    /// </summary>    public class Card    {        //卡片名称        private string cardName = string.Empty;         public string CardName        {            get { return cardName; }            set { cardName = value; }        }        //构造方法        public Card() { }        public Card(string cName)        {            this.cardName = cName;        }    }

2.接下来就是害怕路远的老王,它的饭卡需要先激活,代码如下:

    /// <summary>    /// 老王    /// </summary>    public class MrWang    {         //它有一个饭卡        private Card myCard = new Card("laowang");         public Card MyCard        {            get { return myCard; }        }    } 


3.接下来就是激活饭卡当然要去柜台了,记得在单例模式中已经将这个柜台类实现了,那么我们就拿来用现成的吧:

   

 /// <summary>    /// 柜台类    /// </summary>    public sealed class Counter    {        //在第一次调用类成员时,初始化唯一实例        private static readonly Counter instance = new Counter();        private Counter() { }                //返回类型实例属性        public static Counter Instance        {            get { return instance; }        }         //激活工卡方法        public void ActivationCard(Card card)        {            //激活工卡的过程            Console.WriteLine("{0}的工卡激活了",card.CardName);        }    } 

4.再就是帮助老王第二天去激活卡片的老李,因为老李需要去激活卡片,所以包含激活卡片的操作,代码如下:

 

   /// <summary>    /// 老李    /// </summary>    public class MrLi    {        //激活工卡的方法        public void ActvationCard(Card card)        {            Counter.Instance.ActivationCard(card);        }    } 

5.类型都抽象出来之后当然就是第二天去激活卡片了,主函数调用代码如下:

 

    class Program    {        static void Main(string[] args)        {            //实例化老王            MrWang wang = new MrWang();            //实例化老李            MrLi li = new MrLi();             //将卡片交给老李,老李负责去激活            li.ActvationCard(wang.MyCard);        }    } 

仔细想了一下,这样一来,老李也成了柜台激活卡的代理人了,以后别人也可以委托老李去帮忙激活饭卡了,这不就是代理模式吗?

 

 

 

代理模式

 

代理模式的定义:为其他对象提供一种代理以控制这个对象的访问.

 

更详细的内容是多了一个接口ICounter,那么实现了接口的代理类与具体类的代码如下:

 

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks; namespace 代理模式{    /// <summary>    /// 柜台类也就是具体类提供的功能规则    /// </summary>    public interface ICounter    {        void ActivationCard(Card card);    }    class Program    {        static void Main(string[] args)        {            //实例化老王            MrWang wang = new MrWang();            //实例化老李            MrLi li = new MrLi();             //将卡片交给老李,老李负责去激活            li.ActivationCard(wang.MyCard);        }    }    /// <summary>    /// 卡片类    /// </summary>    public class Card    {        //卡片名称        private string cardName = string.Empty;         public string CardName        {            get { return cardName; }            set { cardName = value; }        }        //构造方法        public Card() { }        public Card(string cName)        {            this.cardName = cName;        }    }    /// <summary>    /// 老王    /// </summary>    public class MrWang    {         //它有一个饭卡        private Card myCard = new Card("laowang");         public Card MyCard        {            get { return myCard; }        }    }    /// <summary>    /// 柜台类    /// </summary>    public sealed class Counter:ICounter    {        //在第一次调用类成员时,初始化唯一实例        private static readonly Counter instance = new Counter();        private Counter() { }                //返回类型实例属性        public static Counter Instance        {            get { return instance; }        }         //激活工卡方法        public void ActivationCard(Card card)        {            //激活工卡的过程            Console.WriteLine("{0}的工卡激活了",card.CardName);        }    }    /// <summary>    /// 老李    /// </summary>    public class MrLi:ICounter    {        //激活工卡的方法        public void ActivationCard(Card card)        {            Counter.Instance.ActivationCard(card);        }    }} 

那么这个接口有什么用呢?

 

在面向对象设计中,对象之间需要进行交互和通信.例如:上面的代理类MrLi调用了具体柜台类Counter的激活饭卡的方法(ActivationCard),那么这个时候代理类MrLi不在代理Counter柜台的激活卡片的功能,而是去另一个CounterNew的柜台去激活,但是CounterNew柜台激活卡片的方法是(CounterActivationCard),怎么办?我们需要去修改调用Counter的类,那么如何降低耦合性呢?当然就是将接口和实现分离开来,这样代理间和柜台对象之间的依赖就是基于接口,而不是实现.

 

例如:目前MrLiCounter之间的调用如下:

 

    /// <summary>    /// 老李    /// </summary>    public class MrLi    {        //激活工卡的方法        public void ActivationCard(Card card)        {            Counter.Instance.ActivationCard(card);        }    } 

那么如果需要加入新的柜台类(CounterNew),它的激活方式叫做(CounterActivationCard),代码如下:

 

    /// <summary>    /// 新的柜台类    /// </summary>    public sealed class NewCounter    {        //在第一次调用类成员时,初始化唯一实例        private static readonly NewCounter instance = new NewConuter();         private NewCounter() { }         //返回类型实例属性        public static NewCounter Instance        {            get { return instance; }        }        //激活工卡方法        public void CounterActivationCard(Card card)        {            //激活工卡的过程            Console.WriteLine("{0}的饭卡被激活!",card.CardName);        }    } 

这样,两个类就紧密的偶合在一起了,Counter类改变,那么MrLi也不得不改变,这时我们如果向使用新的柜台类(NewCounter),也需要修改调用者本身.

 

所以我们需要使用接口分离实现.代码如下:

 

    /// <summary>    /// 柜台类也就是具体类提供的功能规则    /// </summary>    public interface ICounter    {        void ActivationCard(Card card);    }    /// <summary>    /// 柜台类    /// </summary>    public sealed class Counter:ICounter    {        //在第一次调用类成员时,初始化唯一实例        private static readonly Counter instance = new Counter();        private Counter() { }                //返回类型实例属性        public static Counter Instance        {            get { return instance; }        }         //激活工卡方法        public void ActivationCard(Card card)        {            //激活工卡的过程            Console.WriteLine("{0}的工卡激活了",card.CardName);        }    }    /// <summary>    /// 老李    /// </summary>    public class MrLi:ICounter    {        //激活工卡的方法        public void ActivationCard(Card card)        {            Counter.Instance.ActivationCard(card);        }    }    /// <summary>    /// 新的柜台类    /// </summary>    public sealed class NewCounter:ICounter    {        //在第一次调用类成员时,初始化唯一实例        private static readonly NewCounter instance = new NewCounter();         private NewCounter() { }         //返回类型实例属性        public static NewCounter Instance        {            get { return instance; }        }        //激活工卡方法        public void ActivationCard(Card card)        {            //激活工卡的过程            Console.WriteLine("{0}的饭卡被激活!",card.CardName);        }    }

可以看出,有了接口的约束,所有的柜台类都遵循了这个约束将激活卡片的方法统一成了ActivationCard,那么在将来切换对象的时候都可以以一种统一的调用方式去无缝的切换.

 

这时如果细心的朋友还会说,MrLiActivationCard方法中调用的是具体的Counter类型如果换成NewCounter,还是要修改它的代码,你现在只能是不用去修改调用方法了而已,想得好,还记得我们当时学工厂模式吗?它的好处不就是降低耦合吗?用上!

 

加入工厂类,再修改一下MrLi的调用使它的调用依赖于抽象接口而不是具体的实现,代码如下:

 

    /// <summary>    /// 老李    /// </summary>    public class MrLi:ICounter    {        //激活工卡的方法        public void ActivationCard(Card card)        {            Counter.Instance.ActivationCard(card);        }    }    /// <summary>    /// 柜台工厂类    /// </summary>    public class CounterProvider    {        public static ICounter GetCounter()        {            ICounter counter = null;            //确定实例化哪个柜台类            int choose=Console.Read();            switch (choose)            {                case 1:                    counter = Counter.Instance;                      break;                case 2:                    counter = NewCounter.Instance;                    break;                default: break;            }            return counter;        }    }

这样我们就彻底实现了代理模式,并且诠释了如何使用接口的好处和灵活组合模式与灵活理解模式与使用.

 

 

 

应用场景

 

那么代理模式的几种使用场景我们来看一看:


1.远程代理:为了一个对象在不同地址空间提供局部代理.这样可以隐藏一个对象存在于不同地址空间的事实.例如:老王在地点A,老李在地点B,餐厅柜台也在地点B,那么老李就和老王住在一起(都住在A地点),那么老李就是餐厅(地点B)在老王和老李住处(地点A)的代表.

 

2.虚拟代理:是根据需要创建开销很大的对象.通过它来存放实例化需要很长时间的真实对象.例如:老王在A,到餐厅柜台B很费经,而老李刚好在这里(地点B)上班,所以让老李去办事很可行的办法.

 

3.安全代理:用来控制真实对象访问时的权限,例如:老王跟餐厅的柜台MM刚分手,不方便去办理,所以需要借助老李去完成办理.

 

4.智能代理:是指当调用真实的对象时,代理去处理另外一些事情.例如:老李帮助老王办理业务,顺便和餐厅柜台MM说说老王的好话,让他们俩能够复合.

 

 

1 0
原创粉丝点击