C#基础(2)
2021-02-13 18:19
摘要:面向对象编程是很多编程语言的一种重要思想。万物皆对象。有很多种不同个人理解,其实,用的多了,也就能够去体会和领悟这种思想。个人理解:一个类或者接口, 就是对象,面向对象就是对类或者接口的操作,例如用到一个非静态类,需要先new一个这个类的对象,继承接口需要实现接口中的方法等。 此篇博客主要涉及到之前学习面向对象时的一些代码笔记以及总结。
涉及内容: 1、里氏替换原则 2、多态之虚方法 3、多态之抽象类 4、工厂设计模式 5、接口
----------------------------------------------------------------------------------------------------------------------------
面对对象(三大特征,五大原则):
三大特征:封装、继承、多态
五大原则:
单一原则: 一个对象应该只包含一个单一的职责,并且该职责被完整的封装在一个类中。如果一个类中封装了过多的职责,这些职责在并发执行的时候回相互干扰
开放封闭原则: 对扩展开放,对修改代码封闭(主要考虑安全性)
依赖倒转原则: 高层(heigh leve1)模块不该直接依赖低层(low leve1)模块。它们两个应该依赖抽象
里氏替换原则: 子类能够替换它们的父类
接口隔离原则: 客户端不应该依赖那些它不需要的接口
-------------------------------------------------------------------------------------------------------------------------------
封装:封装类,封装成方法 --解决代码冗余
继承:子类继承父类
1、里氏替换原则
a、子类可以赋值给父类
如果有一个方法需要一个父类作为参数,我们可以传第一个子类对象 ,例如:需要一个object类型作为参数,可以传递任何类型的参数 (任何子类都继承object)
b、如果父类中装的是子类对象,则可以将这个父类强转为子类对象
2、多态之虚方法
面向对象多态优点:①解决代码冗余 ▲②:屏蔽各个子类之间的差异,写出通用的代码,适用于每个子类的调用
虚方法的使用:
//父类 public class Person
{ public string Name { get; set; }public Person(string name) { this.Name = name;
} public virtual void SayHello() { Console.WriteLine("我是人类"); } //子类① public class Chinese:Person { public Chinese(string name) : base(name) { } public override void SayHello() { Console.WriteLine("我是中国人,我叫{0}",this.Name); }
} //子类② public class America:Person { public America(string name) : base(name) { } public override void SayHello() { Console.WriteLine("我是美国人,我叫{0}",this.Name); } } //调用实例: Chinese ch = new Chinese("张三"); America a1 = new America("乔布斯"); Person[] per = { ch,a1 }; for (int i = 0; i ) { per[i].SayHello();
} //结果: 两个子类的SayHello方法
以上实例:将父类的方法标记为虚方法,使用关键字virtual,这个方法可以被子类重新写一遍。
在父类的方法前面加上一个virtual,在子类的方法前面加上一个override;如果子类的方法前面不加override,编译器不会报错,但这样的话,就无法通过父类来调用子类的方法,因为这个方法成了子类的独有的方法,只是名字与父类相同而已,与父类无关。通过父类调用子类的方法,屏蔽子类之间的差异
3、多态之抽象类:(常用:工厂设计模式)
问题:运用多态求一个圆与矩形的面积 思考:圆的面积和矩形面积的求法不一样,如何通过写一个父类,然后调用父类的方法,屏蔽子类间的差异?父类根本无法构造方法体
//父类: public abstract class Graph { public abstract double Getarea(); //抽象类没有方法实体 } //子类①:圆 public class Circle : Graph { public double R { get; set; } public Circle(double r) { this.R = r; } public override double Getarea() { return Math.PI * R * R; } } //子类②:矩形 public class Rectangle : Graph { public double Hight { get; set; } public double Width { get; set; } public Rectangle(double width, double hight) { this.Width = width; this.Hight = hight; } public override double Getarea() { return Width * Hight; } } //调用实例: Graph gh = new Circle(3) double circlearea= gh.Getarea(); //求圆的面积 Graph gh2 = new Rectangle(2, 4.2); double rearea = gh2.Getarea(); //求矩形面积
抽象类的特点:
a、抽象类中的抽象成员必须标记为abstract,并且不能有任何实现。方法不能有任何实现是指,方法没有大括号,也没有方法体。 只有大括号,没有方法体的方法叫做空实现。
b、抽象成员必须标记在抽象类中
c、抽象类是有构造函数的,但抽象类不能被实例化
d、子类继承抽象类后,必须把父类中的所有抽象成员都重写。(除非子类也是一个抽象类,则可以不重写)
e、在抽象类中可以包含实例成员,并且它们可以不被子类实现
以上实例说明:不知道如何去写父类这个方法,通过new子类实现抽象方法,屏蔽子类间的差异。上面简单用下抽象类,常用于:工厂设计模式
4、工厂设计模式:
参与者:Product:抽象产品类,将具体产品类的公共代码抽象和提取后封装在一个抽象产品类中(抽象类的抽象方法)
Concerteproduct:具体产品类,将需要创建的各种不同产品对象的相关代码封装到具体产品类中 (继承抽象类的子类的各自方法)
Factory:工厂类,提供一个工厂类创建各种产品,在工厂类中提供一个创建产品的方法,该方法可以根据传入的参数不同创建不同的产品对象
Client: 客户端类,只需要调用工厂类的工厂方法,传入相应的方法即可获得产品对象(实现)
5、接口:
特点:a、接口是一种规范 只要一个类继承了一个接口,这个类必须实现接口的所有成员
b、接口不能被实例化 也就是说不能创建对象
c、接口与接口之间可以继承 并且可以多继承,接口不能继承一个类
d、接口中的成员不能加访问修饰符 默认为public
接口作用很大:首先实现了多继承,另外常用:不同层之间通过调用接口提高安全性(例:业务逻辑层调用数据会话层的接口)。
实现 发布订阅模式(观察者模式):我们作为订阅者不必每次都去查看这个公众号有没有新文章发布, 公众号作为发布者会在合适时间通知我们(继承接口)
我们与公众号之间不再强耦合在一起。公众号不关心谁订阅了它,不管你是男是女还是宠物狗,它只需要定时向所有订阅者发布消息即可(遍历订阅者)
总结:什么时候用虚方法来实现多态?什么时候用抽象类来实现多态?什么时候用接口来实现多态?
在我提供给你的几个类当中,如果说你能抽象出来一个父类,并且这个父类必须写上这几个子类共有的方法,然后你还不知道怎么去写这个方法,就用抽象类来写这个多态。
反之,抽象出来的父类,方法可以写,并且我还要创建这个父类的对象,就用虚方法。
这几个类里面根本就找不出来父类,但它们都有一个共同的行为,共同的能力。这个时候就用接口来实现多态
面向对象多态确实是一个很抽象的东西,具体运用可以根据需求,根据业务逻辑去选择使用。