委托和设计模式(2)(上)

2016-3-28 | 发布者:DotNet

(点击上方蓝字,可快速关注我们)


来源:懒得安分

链接:http://www.cnblogs.com/landeanfen/p/4710174.html


前言:这篇打算从设计模式的角度去解析下委托的使用。我们知道使用委托可以实现对象行为(方法)的动态绑定,从而提高设计的灵活性。上次说过,方法可以理解为委托的实例,站在方法的层面,委托实例的一个非常有用的特性是它既不知道,也不关心其封装方法所属类的详细信息,对它来说最重要的是这些方法与该委托的参数和返回值的兼容性。即只要方法的返回类型和参数表是相同的,则方法与委托类型兼容,方法的名称及方法所属类等信息委托是不关心的。有一定编程经验的大侠们肯定都接触过设计模式,其实设计模式大多数都是面向对象多态特性的体现,通过重写子类方法去展现不同的设计需求,这样看,既然是方法重写,那么方法的参数类型和返回值类型肯定是一致的,这是不是和委托的实例十分相似,这样说来,我们通过多态去实现的设计模式是否可以用委托的形式去代替。博主觉得,为了更好的理解委托,可以从这方面着手试试。。。


此篇简单抽取了几个设计模式分别按照多态和委托的方式去实现,当然这里的重点并不是讲设计模式,而是为了使读者更好地理解委托。所以设计模式的很多细节,本篇可能会略过。


一、简单工厂模式:本篇就借助计算器的例子加以说明。


1、多态实现简单工厂模式。


class Program2

    {

        static void Main(string[] args)

        {

            //1.使用多态实现简单工厂模式

            int x = 8, y = 2;

            var iRes1 = GetObject("+").Compute(x, y);

            var iRes2 = GetObject("-").Compute(x, y);

            var iRes3 = GetObject("*").Compute(x, y);

            var iRes4 = GetObject("/").Compute(x, y);

            Console.WriteLine(iRes1);

            Console.WriteLine(iRes2);

            Console.WriteLine(iRes3);

            Console.WriteLine(iRes4);

            Console.ReadKey();

        }

 

        static Calculator GetObject(string type)

        {

            Calculator oRes = null;

            switch (type)

            { 

                case "+":

                    oRes = new Add();

                    break;

                case "-":

                    oRes = new Subtract();

                    break;

                case "*":

                    oRes = new Multiply();

                    break;

                case "/":

                    oRes = new Divide();

                    break;

            }

            return oRes;

        }

    }

    public class Calculator

    {

        public virtual int Compute(int x, int y)

        {

            return 0;

        }

    }

    public class Add : Calculator

    {

        public override int Compute(int x, int y)

        {

            return x + y;

        }

    }

    public class Subtract : Calculator

    {

        public override int Compute(int x, int y)

        {

            return x - y;

        }

    }

    public class Multiply : Calculator

    {

        public override int Compute(int x, int y)

        {

            return x * y;

        }

    }

    public class Divide : Calculator

    {

        public override int Compute(int x, int y)

        {

            if (y == 0)

            {

                return 0;

            }

            return x / y;

        }

    }


代码应该很容易看懂,直接通过方法的重写去实现,在此就不过多讲解。


2、委托方式实现简单工厂模式。


class Program2

    {

        static void Main(string[] args)

        {

            #region 2.委托实现简单工厂模式

            int x = 8, y = 2;

            var oCalculator = new Calculator();

            var iRes1 = oCalculator.Compute(x, y, oCalculator.Add);

//将方法作为参数传下去

            var iRes2 = oCalculator.Compute(x, y, oCalculator.Subtract);

            var iRes3 = oCalculator.Compute(x, y, oCalculator.Multiply);

            var iRes4 = oCalculator.Compute(x, y, oCalculator.Divide);

 

            Console.WriteLine(iRes1);

            Console.WriteLine(iRes2);

            Console.WriteLine(iRes3);

            Console.WriteLine(iRes4); 

            #endregion

            Console.ReadKey();

        }

    }

    public delegate int DelegateCalculator(int x, int y);

    public class Calculator

    {

    //将方法的实例传递进来,在Compute方法里面执行

        public int Compute(int x, int y, DelegateCalculator calculator)

        {

            return calculator(x, y);

        }

        public int Add(int x, int y)

        {

            return x + y;

        }

        public int Subtract(int x, int y)

        {

            return x - y;

        }

        public int Multiply(int x, int y)

        {

            return x * y;

        }

        public int Divide(int x, int y)

        {

            if (y == 0)

            {

                return 0;

            }

            return x / y;

        }

    }


这里需要定义四个实现方法Add、Subtract、Multiply、Divide,而不用在意这四个方法在哪个类下面,只要这四个方法的的参数和返回值和委托的定义保持一致即可。这也验证了上面说的 “站在方法的层面,委托实例的一个非常有用的特性是它既不知道,也不关心其封装方法所属类的详细信息,对它来说最重要的是这些方法与该委托的参数和返回值的兼容性” 。两种方式得到的结果是相同的:



二、观察者模式:观察者模式最典型的场景就是订阅者和订阅号的场景


1、纯多态方式实现观察者模式:这种代码园子里面非常多。


class Program3

    {

        static void Main(string[] args)

        {

            // 具体主题角色通常用具体自来来实现

            ConcreteSubject subject = new ConcreteSubject();

            subject.Attach(new ConcreteObserver(subject, "Observer A"));

            subject.Attach(new ConcreteObserver(subject, "Observer B"));

            subject.Attach(new ConcreteObserver(subject, "Observer C"));

            subject.SubjectState = "Ready";

            subject.Notify();

            Console.Read();

        }

    }  

    //抽象主题类

    public abstract class Subject

    {

        private IList<Observer> observers = new List<Observer>();

        /// <summary>

        /// 增加观察者

        /// </summary>

        /// <param name="observer"></param>

        public void Attach(Observer observer)

        {

            observers.Add(observer);

        }

        /// <summary>

        /// 移除观察者

        /// </summary>

        /// <param name="observer"></param>

        public void Detach(Observer observer)

        {

            observers.Remove(observer);

        }

        /// <summary>

        /// 向观察者(们)发出通知

        /// </summary>

        public void Notify()

        {

            foreach (Observer o in observers)

            {

                o.Update();

            }

        }

    }

    //具体主题类

    public class ConcreteSubject : Subject

    {

        private string subjectState;

        /// <summary>

        /// 具体观察者的状态

        /// </summary>

        public string SubjectState

        {

            get { return subjectState; }

            set { subjectState = value; }

        }

    }

   //抽象观察者类

    public abstract class Observer

    {

        public abstract void Update();

    }

     //具体观察者

    public class ConcreteObserver : Observer

    {

        private string observerState;

        private string name;

        private ConcreteSubject subject;

 

        /// <summary>

        /// 具体观察者用一个具体主题来实现

        /// </summary>

        public ConcreteSubject Subject

        {

            get { return subject; }

            set { subject = value; }

        }

        public ConcreteObserver(ConcreteSubject subject, string name)

        {

            this.subject = subject;

            this.name = name;

        }

 

        /// <summary>

        /// 实现抽象观察者中的更新操作

        /// </summary>

        public override void Update()

        {

            observerState = subject.SubjectState;

            Console.WriteLine("The observer's state of {0} is {1}", name, observerState);

        }

    }


可以看到虽然已经很好的实现了观察者Observer 和主题Subject之间的分离。但是Subject的内部还是有对观察者的调用:


public void Notify()

{

     foreach (Observer o in observers)

     {

          o.Update();

     }

}


2、多态和委托实现观察者模式。


class Program3

    {

        static void Main(string[] args)

        {

            // 具体主题角色通常用具体自来来实现

            ConcreteSubject subject = new ConcreteSubject();

            //传入的只是观察者的通过方法。

            subject.Attach(new ConcreteObserver(subject, "Observer A").Update);

            subject.Attach(new ConcreteObserver(subject, "Observer B").Update);

            subject.Attach(new ConcreteObserver(subject, "Observer C").Update);

            subject.SubjectState = "Ready";

            subject.Notify();

            Console.Read();

        }

    }

    public delegate void ObserverDelegate();

   //抽象主题类

    public abstract class Subject

    {

        public ObserverDelegate observedelegate;

        /// <summary>

        /// 增加观察者

        /// </summary>

        /// <param name="observer"></param>

        public void Attach(ObserverDelegate observer)

        {

            observedelegate += observer;

        }

        /// <summary>

        /// 移除观察者

        /// </summary>

        /// <param name="observer"></param>

        public void Detach(ObserverDelegate observer)

        {

            observedelegate -= observer;

        }

        /// <summary>

        /// 向观察者(们)发出通知

        /// </summary>

        public void Notify()

        {

            if (observedelegate != null)

            {

                observedelegate();

            }

        }

    }

    //具体主题类

    public class ConcreteSubject : Subject

    {

        private string subjectState;

        /// <summary>

        /// 具体观察者的状态

        /// </summary>

        public string SubjectState

        {

            get { return subjectState; }

            set { subjectState = value; }

        }

    }

   //具体观察者

    public class ConcreteObserver

    {

        private string observerState;

        private string name;

        private ConcreteSubject subject;

 

        /// <summary>

        /// 具体观察者用一个具体主题来实现

        /// </summary>

        public ConcreteSubject Subject

        {

            get { return subject; }

            set { subject = value; }

        }

        public ConcreteObserver(ConcreteSubject subject, string name)

        {

            this.subject = subject;

            this.name = name;

        }

 

        /// <summary>

        /// 实现抽象观察者中的更新操作

        /// </summary>

        public void Update()

        {

            observerState = subject.SubjectState;

            Console.WriteLine("The observer's state of {0} is {1}", name, observerState);

        }

    }


得到结果:



这样设计的优势:


(1)将通知的方法Update通过委托的形式传入主题对象。这样主题对象Subject就完全和观察者隔离。更好地实现了低耦合。


(2)减少了观察者抽象类的定义。使整个设计更加精简。


(3)如果将设计更进一步,观察者这边自定义delegate void ObserverDelegate()这种类型的方法。比如需要执行Update()方法之后还要记录一个日志的操作。如:


//具体观察者

    public class ConcreteObserver

    {

        private string observerState;

        private string name;

        private ConcreteSubject subject;

        /// <summary>

        /// 具体观察者用一个具体主题来实现

        /// </summary>

        public ConcreteSubject Subject

        {

            get { return subject; }

            set { subject = value; }

        }

        public ConcreteObserver(ConcreteSubject subject, string name)

        {

            this.subject = subject;

            this.name = name;

        }

        /// <summary>

        /// 实现抽象观察者中的更新操作

        /// </summary>

        public void Update()

        {

            observerState = subject.SubjectState;

            Console.WriteLine("The observer's state of {0} is {1}", name, observerState);

        }

        public void Log()

        {

            Console.WriteLine("Log:Update方法执行完成");

        }

    }


那么在客户端调用时只需要将Log方法以委托的形式传入即可:


static void Main(string[] args)

{

      // 具体主题角色通常用具体自来来实现

     ConcreteSubject subject = new ConcreteSubject();

    //传入的只是观察者的通过方法。

    var obj = new ConcreteObserver(subject, "Observer A");

    subject.Attach(obj.Update);

    subject.Attach(obj.Log);

 

    subject.SubjectState = "Ready";

    subject.Notify();

    Console.Read();

}


是不是显得更灵活一点。如果是纯多态的方式,由于Subject里面指定了调用Update()方法,所以当需要增加Log方法的时候代码的改变量要大。






热门文章

更多

辣妈帮

父母才是孩子最重要的老师,请花2分钟看看吧!

父母才是孩子最重要的老师,请花2分钟看看吧!

教育孩子,一直是个难题。有的父母会在小孩上学后,就把这方面的事情,放到学校、老师上,而忽略了自己才是孩子最重要的老师!如果您的孩子在上学,请花2分钟看看吧!1家影响孩子成绩的主要因素不是学校而是家庭...
无巧不成书 • 
产房纪实:疯狂“二胎”!!

产房纪实:疯狂“二胎”!!

来源:文汇教育(ID:wenhuieducation)作者:唐闻佳  3月11日上午9点,接到电话,熊瑛快速换上手术服冲进产科病房尽头的一间手术室。她是“临时去帮忙的”,这台“二胎”剖宫产术有点麻烦。   “现在外头都...
向辣妈进军 • 
开团 扎克伯格家的《宝宝的量子物理学》

开团 扎克伯格家的《宝宝的量子物理学》

今天推荐的是咱们另一个公众号“奇妙盒子”的团购。注:4月1号晚上截团。我们在奇妙盒子开团的这套不寻常的绘本书,不是因为这套书有多火,有多高大上,而是想告诉孩子们,这个广袤的世界,还有那么多让人着迷和...
宝宝餐餐见 • 
世界儿歌日,和孩子一起唱响爱!

世界儿歌日,和孩子一起唱响爱!

“小兔子乖乖,把门儿开开”、“小燕子,穿花衣”、“世上只有妈妈好”……一首首耳熟能详的动人童谣伴随和影响了一代又一代人的成长,也勾起了太多人美好的童年回忆。但你知道么?早在三十年前,为了倡导“关爱...
微亲子 • 
孩子上幼儿园后,这6种行为不可忽视(转给家长)

孩子上幼儿园后,这6种行为不可忽视(转给家长)

孩子刚上幼儿园初期会不适应幼儿园有一些哭闹现象,或者上了一段时间的幼儿园也有可能害怕,一旦孩子出现了以下6种行为,爸妈要引起重视,务必帮助孩子及时调整心情。1.在幼儿园不说话宝宝在幼儿园里不说话,坐...
幼儿园教育 • 
加载更多

 更多体育迷