最近在复习C#面向对象,也就是说常说的3大特性:封装、继承和多态。首先说一下封装,其实封装最大的目的也是为了实现代码的解耦和重用、代码也是安全的(对外它隐藏了具体的实现,就好比我们拿个遥控器就能操作电视机,而无须知道其内部实现);C#中很多地方都用到了封装,可以将一个具体的功能代码封装成一个方法,供外界调用就是一个封装。
再说一下继承吧。首先要搞明白的是,继承是类与类之间的关系,那么必然有一个父类,一个子类(可以理解为父亲和儿子的关系),父类是相对子类更抽象的类,而子类是相对父类更具体的类(可以理解为父类能做的事儿,子类继承后都可以做,这里有一个特例,父类如果将一个方法或字段设为Sealed,私有的,子类是继承不到的;而子类能做的事儿,父类不一定能做,即在子类中新增的方法),C#有2种继承,体现为父类中有虚方法(virtual)、父类是抽象类(abstract),这2种都可以供子类继承,根据2种实现时语法上的不同,他们的区别是:
1.如果一个需求是很模糊,很广泛的,这是考虑抽象类,而不是虚方法。
2.如果一个父类要求有代码实现,那么就必须用虚方法,因为抽象方法是不允许有代码实现的;
3.如果强制要求一个子类必须实现父类中的方法,那么父类必须用抽象类,如果没有这样的要求,那么父类可以用虚方法;
4.抽象类不能被实例化(但可以有构造函数),可以有实例成员也可以有抽象成员。
需要说明的是,假如父类是抽象类,而如果子类也不想实现父类的方法,只要子类也是抽象类即可,这样以来,实现的代码就交给子类的下一代(个)子类来实现。
判断继承关系:
子类 is (a) 父类;
转换,子类 as 父类。(这个方法转换成功,返回父类对象;转换失败,返回null)
继承的好处:
1.代码重用;
2.继承就是为了实现多态而准备的,多态就是一个类的多种状态(说的很模糊);这里提到一个概念,叫“里氏替换原则”,父类变量指向子类对象。多态的目的是,为了程序的可扩展性(开放封闭原则,对修改封闭,对扩展开放);下面用一个具体实例说明问题:
需求是,要实现一个计算器,要求不论多复杂的算法,调用者只需要掉“计算”这个方法就能得到自己想要的结果,而且计算方法还会不断地扩展。这个时候考虑虚方法是不行的,因为虚方法有代码实现,所以采用抽象类是最合适不过的。抽象类的代码如下:
public abstract class Calculator
{
public int Number1
{
get;
set;
}
public int Number2
{
get;
set;
}
//2个构造函数
public Calculator()
{
}
public Calculator(int n1,int n2)
{
this.Number1 = n1;
this.Number2 = n2;
}
public abstract int Jisuan();
}
再定义一个类库,里面的类来实现上面这个类即可(如果上面的类在另外一个类库中,注意引用)。举例:加法
public class AddFa : Calculator
{
public AddFa(int n1,int n2):base(n1,n2)
{
}
public override int Jisuan()
{
return Number1 + Number2;
}
}
这个时候,用一个控制台来测试上面的加法类:
static void Main(string[] args)
{
Console.WriteLine("请输入第一个数:");
int number1 = int.Parse(Console.ReadLine());
Console.WriteLine("请输入操作符:");
string op = Console.ReadLine();
Console.WriteLine("请输入第二个数:");
int number2 = int.Parse(Console.ReadLine());
Calculator cal = MCop(op, number1, number2);
int? iResult = cal.Jisuan(); //这里调用的是子类的计算方法
if (iResult!=null)
{
Console.WriteLine("计算结果是:{0}",iResult.ToString());
}
Console.ReadKey();
}
/// <summary>
/// 简单工厂设计模式(返回值是一个子类,“产品类”;Calculator是父类,“工厂类”,父类变量指向子类对象)
/// </summary>
/// <param name="op"></param>
/// <param name="number1"></param>
/// <param name="number2"></param>
/// <returns></returns>
static Calculator MCop(string op, int number1, int number2)
{
Calculator cal1 = null;
switch (op)
{
case "+": cal1 = new AddFa(number1, number2); break;
case "-": cal1 = new JianFa(number1, number2); break;
}
return cal1;
}
注意,当下面的方法MCop执行完毕后,返回的是产品类,再在主函数中调Jisuan(),就得到想要的结果(“产品”),这就是“简单工厂设计模式”。
============================================================================================
Static关键字: 静态成员(静态字段、静态方法)
1.类中静态成员不能通过类的实例对象名来访问,只能通过类名来访问。
2.在静态函数中不能使用this,因为this代表类的对象;
3.静态成员在整个程序中是共享的,一个地方改变了,其他用到它的地方都会发生改变;而且静态成员占用的内存资源直到程序退出才释放;而实例成员超出其作用域就会释放掉,一个实例成员发生变化,不影响其他实例。
4.静态类中只能包含静态成员,而普通类(不含Static),既可以包含静态成员,也可以包含实例成员。
5.静态类不能被继承,因为他是抽象的(abstract,不能实例化)也是密封的(Sealed,不能被继承).
6.静态类有静态构造函数,其必须加Static关键字;静态构造函数是由系统来调用,而不是程序员来调用的。
7.静态类中的静态成员不能有访问修饰符,也不能有参数(不知道谁传参数进去),默认是Private(私有的).
8.静态类只能继承自Object类,不能实现任何接口(接口中的成员都是实例成员)。
静态类使用不多,那么它的应用场景有:
一般工具类(SQLHelper)、工具方法写成静态的,共有的、不变的属性也写成静态的;其余的属性考虑到内存占用情况,写成普通的(实例的)。
============================================================================================
new关键字的用法:
1.实例化,创建对象;
2.如果在继承中,将子类的同名方法加一个new关键字,则表示隐藏父类继承过来的方法(因为没有通过override重写父类中的方法,故通过父类类型变量调用相同方法时访问的是父类自己的方法,而用子类类型变量调用则访问的是子类中的方法),简单点说,就是父类中的方法和子类中的方法不再有任何关系,跟继承不一样。