多肽
多肽,就是一个行为,在不同的环境下不同表现,就想人一样,在不同的环境下会体现出不同的性格,然后做出不同的行为。多肽的基本概念,大家都知道,但是,我这里将的是深入的分析和理解。涉及的内容会比较多;所以要慢慢的总结和写;比如if else ,switch case ,委托,泛型委托,事件,观察着设计模式,重载,多肽,面向面向过程编程,面向对象编程,函数式编程;记住,要把具体的实现的方式,写在方法的外部,才有良好的扩展性;这就是我们一直提倡的面向接口编程,而不是面向具体的实现编程;
c#中有编译时多肽和运行时多肽
先从问题的源头开始看起;
public class Person { public void SayHello(string name) { Console.WriteLine("你好"+name); //“你好” 具体额语言实现方式,你写在里面,如果有扩展你可能会这么做; } public void SayEnglishHello(string name) { Console.WriteLine("hello" + name); //“你好” 具体额语言实现方式,你写在里面,如果有扩展你可能会这么做; } public void SayJanpanesesHello(string name) { Console.WriteLine("空你几哇" + name); //“你好” 具体额语言实现方式,你写在里面,如果有扩展你可能会这么做; } //全世界有几百个国家,你就要写几百个同样的方法,我靠; //优化原则,将我们的具体实现,放在外面; //前面三种,就叫:将具体的实现,写死了,我靠; public void SaySomething(string languge,string name) { Console.WriteLine(languge + name); } } //还有没有更好的优化呢
上面的代码有点小菜了~
我们先看面向过程的编写方式,也就是刚毕业的学生都会写的方法;
public enum Eniorment { en1 = 9, //九点上班 en2 = 12, //12点吃饭 en3 = 6 //六点下班 } public class Person { public void Test(Eniorment en) { //你可能会说这里用switch case 来进行优化,其实本质上都一样的;我这里就不多写; if (en == Eniorment.en1) { WakeUp(); } else if (en == Eniorment.en2) { Eat(); } else if (en == Eniorment.en3) { OffWork(); } //可能还有很多的情况 } private void WakeUp() { } private void Eat() { } private void OffWork() { } }
我们现在来看面向对象的编程的风格,不同环境(条件)下,同一个动作的不同表现;记住!!不同环境!!!,这里的不同表现是可以抽象成同一动作的,这个非常重要!!!;
/// <summary> /// 对动作的抽象 /// </summary> public interface IAction { void DoAction(); } //下面是对接口的实现 public class EniormentNineClock : IAction //九点起床; { public void DoAction() { } } public class EniormentTwelveClock : IAction //12点吃午饭 { public void DoAction() { } } public class EniormentSixClock : IAction //六点下班 { public void DoAction() { } } public class Person { public void Test(IAction a) { a.DoAction(); //要把具体的实现写在函数Test的外部; } }
然后,除了用面向对象的方式进行优化,我们还可以用c#中的委托,来进行另一种方式的实现
先看委托的定义:
委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性,
以将多个方法赋给同一个委托,或者叫将多个方法绑定到同一个委托,当调用这个委托的时候,将依次调用其所绑定的方法
public delegate void ActionEventHandler(); public class Person { //按照面向过程的写法,我们是要进行Eniorment 枚举进行传递的,然后,现在我们直接传递委托变量;或者叫“方法具体实现的一个引用” //至于怎么实现,我们再调用的时候进行判读; public void Test(ActionEventHandler action) { action(); } } public class Action { public static void WakeUp() { } public static void Eat() { } public static void OffWork() { } } class Program { static void Main(string[] args) { //ActionEventHandler wake = new ActionEventHandler(Action.WakeUp); ActionEventHandler wake = Action.WakeUp; ActionEventHandler Eat = Action.Eat; ActionEventHandler OffWork =Action.OffWork; Person p = new Person(); p.Test(wake); Console.Read(); } } }
对上面的代码,我们再进行一个简单的优化;
在这里,delegate1和我们平时用的string类型的变量没有什么分别,而我们知道,并不是所有的字段都应该声明成public,合适的做法是应该public的时候public,应该private的时候private。我们先看看如果把 delegate1 声明为 private会怎样?结果就是:这简直就是在搞笑。因为声明委托的目的就是为了把它暴露在类的客户端进行方法的注册,你把它声明为private了,客户端对它根本就不可见,那它还有什么用?
再看看把delegate1 声明为 public 会怎样?结果就是:在客户端可以对它进行随意的赋值等操作,严重破坏对象的封装性。
public delegate void ActionEventHandler(); //破会了oop的原则,暴露了 在客户端可以对它进行随意的赋值等操作,严重破坏对象的封装性 //?答案是使用属性对字段进行封装。 private string _name; public string Name { get { return _name; } set { value = _name; } } public void Test(ActionEventHandler action) { if (action != null) { action(); } } }
事件其实没什么不好理解的,声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已。
于是,Event出场了,它封装了委托类型的变量,使得:在类的内部,不管你声明它是public还是protected,它总是private的。在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同。
public class Person { public delegate void ActionEventHandler(); public event ActionEventHandler EventHandler; //被编译成 私有字段,因为,你无法使用= 操作符号进行赋值,你智能用+= 或者-= 来进行事件的注册于注销 public void Test() { if (EventHandler != null) { EventHandler(); } } }
我们在来想想一个更加实际的例子,我们的额Timer,当到达某个时间点,我们就执行一些方法;
如果我们不使用事件将具体的实现,在类的外部进行注册,
那么再如果别人讲代码封装成dll 就完全没有扩展性而言的呀
函数式编程的具体实现方式;
参考文献;http://blog.jobbole.com/102236/
http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx