分享

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

 weijianian 2016-08-07


来源:懒得安分

链接: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 observers = new List();

        ///

        /// 增加观察者

        ///

        ///

        public void Attach(Observer observer)

        {

            observers.Add(observer);

        }

        ///

        /// 移除观察者

        ///

        ///

        public void Detach(Observer observer)

        {

            observers.Remove(observer);

        }

        ///

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

        ///

        public void Notify()

        {

            foreach (Observer o in observers)

            {

                o.Update();

            }

        }

    }

    //具体主题类

    public class ConcreteSubject : Subject

    {

        private string subjectState;

        ///

        /// 具体观察者的状态

        ///

        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;

 

        ///

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

        ///

        public ConcreteSubject Subject

        {

            get { return subject; }

            set { subject = value; }

        }

        public ConcreteObserver(ConcreteSubject subject, string name)

        {

            this.subject = subject;

            this.name = name;

        }

 

        ///

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

        ///

        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;

        ///

        /// 增加观察者

        ///

        ///

        public void Attach(ObserverDelegate observer)

        {

            observedelegate += observer;

        }

        ///

        /// 移除观察者

        ///

        ///

        public void Detach(ObserverDelegate observer)

        {

            observedelegate -= observer;

        }

        ///

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

        ///

        public void Notify()

        {

            if (observedelegate != null)

            {

                observedelegate();

            }

        }

    }

    //具体主题类

    public class ConcreteSubject : Subject

    {

        private string subjectState;

        ///

        /// 具体观察者的状态

        ///

        public string SubjectState

        {

            get { return subjectState; }

            set { subjectState = value; }

        }

    }

   //具体观察者

    public class ConcreteObserver

    {

        private string observerState;

        private string name;

        private ConcreteSubject subject;

 

        ///

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

        ///

        public ConcreteSubject Subject

        {

            get { return subject; }

            set { subject = value; }

        }

        public ConcreteObserver(ConcreteSubject subject, string name)

        {

            this.subject = subject;

            this.name = name;

        }

 

        ///

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

        ///

        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;

        ///

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

        ///

        public ConcreteSubject Subject

        {

            get { return subject; }

            set { subject = value; }

        }

        public ConcreteObserver(ConcreteSubject subject, string name)

        {

            this.subject = subject;

            this.name = name;

        }

        ///

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

        ///

        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方法的时候代码的改变量要大。




    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多