一、多态
里氏替换原则:
任何能用基类的地方,可以用子类代替,反过来不行。子类能够在基类的基础上增加新的行为。面向对象设计的基本原则之一。
开放封闭原则:
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。关键是抽象,将一个功能的通用部分和实现细节部分清晰的分离开来。所有面向对象原则的核心。
虚方法实现多态:
1 using System; 2 3 namespace Polymorphism 4 { 5 // 鸟类:父类 6 public class Bird 7 { 8 // 吃:虚方法 9 public virtual void Eat() 10 { 11 Console.WriteLine("我是一只小小鸟,我喜欢吃虫子~"); 12 } 13 } 14 15 // 喜鹊:子类 16 public class Magpie:Bird 17 { 18 // 重写父类中Eat方法 19 public override void Eat() 20 { 21 Console.WriteLine("我是一只喜鹊,我喜欢吃虫子~"); 22 } 23 } 24 25 // 老鹰:子类 26 public class Eagle:Bird 27 { 28 // 重写父类中Eat方法 29 public override void Eat() 30 { 31 Console.WriteLine("我是一只老鹰,我喜欢吃肉~"); 32 } 33 } 34 35 // 企鹅:子类 36 public class Penguin:Bird 37 { 38 // 重写父类中Eat方法 39 public override void Eat() 40 { 41 Console.WriteLine("我是一只小企鹅,我喜欢吃鱼~"); 42 } 43 } 44 45 class MainClass 46 { 47 public static void Main (string[] args) 48 { 49 //创建一个Bird基类数组,添加基类Bird对象,Magpie对象,Eagle对象,Penguin对象 50 Bird[] birds = { 51 new Bird(), 52 new Magpie(), 53 new Eagle(), 54 new Penguin() 55 }; 56 //遍历一下birds数组 57 foreach (Bird bird in birds) 58 { 59 bird.Eat(); 60 } 61 Console.ReadKey(); 62 } 63 } 64 }
运行结果:
抽象实现多态:
1 using System; 2 3 namespace Polymorphism 4 { 5 // 鸟类:父类 6 public abstract class Bird 7 { 8 // 吃:虚方法 9 public abstract void Eat(); 10 } 11 12 // 喜鹊:子类 13 public class Magpie:Bird 14 { 15 // 重写父类中Eat方法 16 public override void Eat() 17 { 18 Console.WriteLine("我是一只喜鹊,我喜欢吃虫子~"); 19 } 20 } 21 22 // 老鹰:子类 23 public class Eagle:Bird 24 { 25 // 重写父类中Eat方法 26 public override void Eat() 27 { 28 Console.WriteLine("我是一只老鹰,我喜欢吃肉~"); 29 } 30 } 31 32 // 企鹅:子类 33 public class Penguin:Bird 34 { 35 // 重写父类中Eat方法 36 public override void Eat() 37 { 38 Console.WriteLine("我是一只小企鹅,我喜欢吃鱼~"); 39 } 40 } 41 42 class MainClass 43 { 44 public static void Main (string[] args) 45 { 46 //创建一个Bird基类数组,添加基类Bird对象,Magpie对象,Eagle对象,Penguin对象 47 Bird[] birds = { 48 new Magpie(), 49 new Eagle(), 50 new Penguin() 51 }; 52 //遍历一下birds数组 53 foreach (Bird bird in birds) 54 { 55 bird.Eat(); 56 } 57 Console.ReadKey(); 58 } 59 } 60 }
运行结果:
接口实现多态:
1 using System; 2 3 namespace Polymorphism 4 { 5 //飞 6 public interface IFlyable 7 { 8 void Fly(); 9 } 10 11 // 鸟类:父类 12 public abstract class Bird 13 { 14 // 吃:虚方法 15 public abstract void Eat(); 16 } 17 18 // 喜鹊:子类 19 public class Magpie:Bird,IFlyable 20 { 21 public void Fly () 22 { 23 Console.WriteLine ("我是一只喜鹊,我会飞~"); 24 } 25 26 // 重写父类中Eat方法 27 public override void Eat() 28 { 29 Console.WriteLine("我是一只喜鹊,我喜欢吃虫子~"); 30 } 31 } 32 33 // 老鹰:子类 34 public class Eagle:Bird,IFlyable 35 { 36 public void Fly () 37 { 38 Console.WriteLine ("我是一只老鹰,我可以飞~"); 39 } 40 41 // 重写父类中Eat方法 42 public override void Eat() 43 { 44 Console.WriteLine("我是一只老鹰,我喜欢吃肉~"); 45 } 46 } 47 48 // 企鹅:子类 49 public class Penguin:Bird 50 { 51 // 重写父类中Eat方法 52 public override void Eat() 53 { 54 Console.WriteLine("我是一只小企鹅,我喜欢吃鱼~"); 55 } 56 } 57 58 class MainClass 59 { 60 public static void Main (string[] args) 61 { 62 //创建一个Bird基类数组,添加基类Bird对象,Magpie对象,Eagle对象,Penguin对象 63 Bird[] birds = { 64 new Magpie(), 65 new Eagle(), 66 new Penguin() 67 }; 68 //遍历一下birds数组 69 foreach (Bird bird in birds) 70 { 71 bird.Eat(); 72 } 73 74 Console.WriteLine ("-----------------------"); 75 76 //创建一个IFlyable接口数组,添加 Magpie对象,Eagle对象 77 IFlyable[] flys = { 78 new Magpie(), 79 new Eagle() 80 }; 81 //遍历一下flys数组 82 foreach (IFlyable fly in flys) 83 { 84 fly.Fly(); 85 } 86 Console.ReadKey(); 87 } 88 } 89 }
运行结果:
二、委托
委托:将方法作为参数传递。
1 using System; 2 3 namespace Delegate 4 { 5 public delegate void GreetingDelegate(string name); 6 7 class People 8 { 9 public static void Speak(string name,GreetingDelegate _delegate) 10 { 11 _delegate (name); 12 } 13 } 14 class Language 15 { 16 public static void EnglishGreeting(string name) 17 { 18 Console.WriteLine ("Good Morning,"+name); 19 } 20 public static void ChineseGreeting(string name) 21 { 22 Console.WriteLine ("早上好,"+name); 23 } 24 } 25 26 class MainClass 27 { 28 public static void Main (string[] args) 29 { 30 GreetingDelegate greetingDelegate; 31 greetingDelegate = Language.EnglishGreeting ;//委托第一次绑定时,须用“=” 32 People.Speak("Jason",greetingDelegate); 33 greetingDelegate -= Language.EnglishGreeting; 34 greetingDelegate += Language.ChineseGreeting ; 35 People.Speak("杰森",greetingDelegate); 36 } 37 } 38 }
运行结果:
三、事件
事件:对委托类型的变量的封装;在类的内部,不管你声明的事件是public还是protected,它总是private的;在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同。
1 using System; 2 3 namespace Delegate 4 { 5 public delegate void GreetingDelegate(string name); 6 7 class People 8 { 9 public static event GreetingDelegate greetingEvent; 10 public static void Speak(string name) 11 { 12 greetingEvent(name); 13 } 14 } 15 class Language 16 { 17 public static void EnglishGreeting(string name) 18 { 19 Console.WriteLine ("Good Morning,"+name); 20 } 21 public static void ChineseGreeting(string name) 22 { 23 Console.WriteLine ("早上好,"+name); 24 } 25 } 26 27 class MainClass 28 { 29 public static void Main (string[] args) 30 { 31 People.greetingEvent += Language.EnglishGreeting; 32 People.Speak ("Jason"); 33 People.greetingEvent -= Language.EnglishGreeting; 34 People.greetingEvent += Language.ChineseGreeting; 35 People.Speak ("杰森"); 36 } 37 } 38 }
运行结果:
四、匿名委托
匿名委托:也叫匿名方法,将代码块当做参数传递,因为不需要创建单独的方法,因此减少了实例化委托所需要的开销;
1 using System; 2 3 namespace Delegate 4 { 5 public delegate void GreetingDelegate(string name); 6 class People 7 { 8 public static void Speak(string name,GreetingDelegate _delegate) 9 { 10 _delegate (name); 11 } 12 } 13 14 class MainClass 15 { 16 public static void Main (string[] args) 17 { 18 GreetingDelegate greetingDelegate = delegate(string name) { 19 Console.WriteLine ("Good Morning,"+name); 20 }; 21 People.Speak ("Jason",greetingDelegate); 22 23 GreetingDelegate greetingDelegate_1 = delegate(string name) { 24 Console.WriteLine ("早上好,"+name); 25 }; 26 People.Speak ("杰森",greetingDelegate_1); 27 } 28 } 29 }
在使用匿名方法时候,要注意不能使用跳转语句跳转到该匿名方法的外部,同样不能用跳转语句从外部跳转到匿名方法内部,匿名方法中不能访问不安全代码(unsafe),也不能访问在匿名方法外部使用的ref和out参数。在实际问题中可能遇到的问题要比上面的代码复杂得多,在匿名方法中捕获变量就是难点之一。
运行结果:
五、Lambda表达式
Lambda表达式:比匿名委托代码更加简洁,运算符"()=>",
1 using System; 2 3 namespace Delegate 4 { 5 public delegate void GreetingDelegate(string name); 6 class People 7 { 8 public static void Speak(string name,GreetingDelegate _delegate) 9 { 10 _delegate (name); 11 } 12 } 13 14 class MainClass 15 { 16 public static void Main (string[] args) 17 { 18 GreetingDelegate greetingDelegate = (string name) => 19 Console.WriteLine ("Good Morning,"+name); 20 People.Speak ("Jason",greetingDelegate); 21 22 GreetingDelegate greetingDelegate_1 = (string name) => { 23 Console.WriteLine ("早上好," + name); 24 }; 25 People.Speak ("杰森",greetingDelegate_1); 26 } 27 } 28 }
运行结果:
六、观察者模式
观察者模式:有时又被称为发布(publish )-订阅(Subscribe)模式、模型-视图(View)模式、源-收听者(Listener)模式或从属者模式;观察者设计模式定义了对象间的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
实现观察者模式有很多形式,比较直观的一种是使用一种“注册——通知——撤销注册”的形式:
1、观察者(Observer)将自己注册到被观察对象(Subject)中,被观察对象将观察者存放在一个容器(Container)里。
2、被观察对象发生了某种变化(如图中的SomeChange),从容器中得到所有注册过的观察者,将变化通知观察者。
3、观察者告诉被观察者要撤销观察,被观察者从容器中将观察者去除。
实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。
1 using System; 2 3 namespace Delegate 4 { 5 public class Heater 6 { 7 private int temperature; 8 public delegate void BoilHandler(int param); 9 public event BoilHandler BoilEvent; 10 public void BoilWater() 11 { 12 for (int i = 0; i <= 100; i++) 13 { 14 temperature = i; 15 if (temperature > 95) 16 { 17 if (BoilEvent != null) 18 { 19 BoilEvent(temperature); // 调用所有注册对象的方法 20 } 21 } 22 } 23 } 24 } 25 public class Alarm 26 { 27 public void MakeAlert(int param) 28 { 29 Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:", param); 30 } 31 } 32 public class Display 33 { 34 public static void ShowMsg(int param) // 静态方法 35 { 36 Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", param); 37 } 38 } 39 class Program 40 { 41 static void Main() 42 { 43 Heater heater = new Heater(); 44 Alarm alarm = new Alarm(); 45 heater.BoilEvent += alarm.MakeAlert; // 注册方法 46 heater.BoilEvent += (new Alarm()).MakeAlert; // 给匿名对象注册方法 47 heater.BoilEvent += Display.ShowMsg; // 注册静态方法 48 heater.BoilWater(); // 烧水,会自动调用注册过对象的方法 49 } 50 } 51 }
运行结果:
七、.NET 框架中的委托和事件
.NET Framework 的编码规范:
1. 委托类型的名称都应该以 EventHandler 结束。
2. 委托的原型定义:有一个void 返回值,并接受两个输入参数:一个Object 类型,一个EventArgs 类型(或继承自EventArgs)。
3. 事件的命名为委托去掉 EventHandler 之后剩余的部分。
4. 继承自 EventArgs 的类型应该以EventArgs 结尾。
补充说明:
1. 委托声明原型中的Object 类型的参数代表了Subject,也就是监视对象。
2. EventArgs 对象包含了Observer 所感兴趣的数据。
1 using System; 2 3 namespace Delegate 4 { 5 public class Heater 6 { 7 private int temperature; 8 public string type = "RealFire 001"; // 添加型号作为演示 9 public string area = "China Xian"; // 添加产地作为演示 10 11 public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e); 12 13 public event BoiledEventHandler Boiled; // 声明事件 14 15 // 定义 BoiledEventArgs 类,传递给 Observer 所感兴趣的信息 16 public class BoiledEventArgs : EventArgs 17 { 18 public readonly int temperature; 19 public BoiledEventArgs(int temperature) 20 { 21 this.temperature = temperature; 22 } 23 } 24 // 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视 25 protected virtual void OnBoiled(BoiledEventArgs e) 26 { 27 if (Boiled != null) 28 { 29 Boiled(this, e); // 调用所有注册对象的方法 30 } 31 } 32 33 public void BoilWater() 34 { 35 for (int i = 0; i <= 100; i++) 36 { 37 temperature = i; 38 if (temperature > 95) 39 { 40 // 建立BoiledEventArgs 对象。 41 BoiledEventArgs e = new BoiledEventArgs(temperature); 42 OnBoiled(e); // 调用 OnBolied 方法 43 } 44 } 45 } 46 47 public class Alarm 48 { 49 public void MakeAlert(Object sender, Heater.BoiledEventArgs e) 50 { 51 Heater heater = (Heater)sender; // 这里是不是很熟悉呢? 52 53 // 访问 sender 中的公共字段 54 Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type); 55 Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature); 56 } 57 } 58 public class Display 59 { 60 public static void ShowMsg(Object sender, Heater.BoiledEventArgs e) // 静态方法 61 { 62 Heater heater = (Heater)sender; 63 Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type); 64 Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature); 65 } 66 } 67 68 class Program 69 { 70 static void Main() 71 { 72 Heater heater = new Heater(); 73 Alarm alarm = new Alarm(); 74 heater.Boiled += alarm.MakeAlert; //注册方法 75 heater.Boiled += (new Alarm()).MakeAlert; //给匿名对象注册方法 76 heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert); //也可以这么注册 77 heater.Boiled += Display.ShowMsg; //注册静态方法 78 heater.BoilWater(); //烧水,会自动调用注册过对象的方法 79 } 80 } 81 } 82 }
运行结果:
文章参考自:http://www.cnblogs.com/SkySoot/archive/2012/04/05/2433639.html
附加观察者模板:
1 using System; 2 using System.Collections.Generic; 3 4 namespace Delegate 5 { 6 /// <summary> 7 /// 抽象主题类 8 /// </summary> 9 public abstract class Subject 10 { 11 private IList<Observer> observers = new List<Observer>(); 12 13 /// <summary> 14 /// 增加观察者 15 /// </summary> 16 /// <param name="observer"></param> 17 public void Attach(Observer observer) 18 { 19 observers.Add(observer); 20 } 21 22 /// <summary> 23 /// 移除观察者 24 /// </summary> 25 /// <param name="observer"></param> 26 public void Detach(Observer observer) 27 { 28 observers.Remove(observer); 29 } 30 31 /// <summary> 32 /// 向观察者(们)发出通知 33 /// </summary> 34 public void Notify() 35 { 36 foreach (Observer o in observers) 37 { 38 o.Update(); 39 } 40 } 41 } 42 43 /// <summary> 44 /// 抽象观察者类,为所有具体观察者定义一个接口,在得到通知时更新自己 45 /// </summary> 46 public abstract class Observer 47 { 48 public abstract void Update(); 49 } 50 51 /// <summary> 52 /// 具体观察者或具体通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。 53 /// </summary> 54 public class ConcreteSubject : Subject 55 { 56 private string subjectState; 57 58 /// <summary> 59 /// 具体观察者的状态 60 /// </summary> 61 public string SubjectState 62 { 63 get { return subjectState; } 64 set { subjectState = value; } 65 } 66 } 67 68 /// <summary> 69 /// 具体观察者,实现抽象观察者角色所要求的更新接口,已是本身状态与主题状态相协调 70 /// </summary> 71 public class ConcreteObserver : Observer 72 { 73 private string observerState; 74 private string name; 75 private ConcreteSubject subject; 76 77 /// <summary> 78 /// 具体观察者用一个具体主题来实现 79 /// </summary> 80 public ConcreteSubject Subject 81 { 82 get { return subject; } 83 set { subject = value; } 84 } 85 86 public ConcreteObserver(ConcreteSubject subject, string name) 87 { 88 this.subject = subject; 89 this.name = name; 90 } 91 92 /// <summary> 93 /// 实现抽象观察者中的更新操作 94 /// </summary> 95 public override void Update() 96 { 97 observerState = subject.SubjectState; 98 Console.WriteLine("The observer's state of {0} is {1}", name, observerState); 99 } 100 } 101 class Program 102 { 103 static void Main() 104 { 105 // 具体主题角色通常用具体自来来实现 106 ConcreteSubject subject = new ConcreteSubject (); 107 108 subject.Attach (new ConcreteObserver (subject, "Observer A")); 109 subject.Attach (new ConcreteObserver (subject, "Observer B")); 110 subject.Attach (new ConcreteObserver (subject, "Observer C")); 111 112 subject.SubjectState = "Ready"; 113 subject.Notify (); 114 115 Console.Read (); 116 } 117 } 118 }
运行结果: