面向对象

C#是面向对象的语言,面向对象(Object Oriented,OO)是一种编程思想,强调系统的结构应该直接与现实世界的结构相对应,应该围绕现实世界中的对象来构造系统,而不是围绕功能来构造系统。

所有面向对象的语言都具有三个基本的特征,它们是:

  • 封装:把客观事物封装成类,并将类内部实现隐藏,以保证数据的完整性。
  • 继承:通过继承可以复用父类的代码。
  • 多态:允许每个对象以适合自身的方式去响应共同的消息。

C#中的面向对象编程指的是运用这三个基本的特征来编写程序。

封装

封装指的是把类的内部实现隐藏起来,不让对象直接对其进行操作。C#提供了属性机制对内部的状态进行操作。在C#中,封装可以通过public,protected,private,internal来体现。为什么使用封装,因为有的时候,我们把内部的数据定义为public之后,外部对象可以进行任意的操作,很可能导致不符合逻辑规则。面向对象的封装特性,是一种保护状态数据完整性的方法,在面向对象编程中,应更多的定义私有字段,并且使用属性机制来对私有字段进行访问。

成员访问修饰符

封装的好处是数据安全,提供重用性,分工合作和方便构建大型复杂的项目

继承

在C#中,一个类可以继承另外一个已有的类(密封类除外),被继承的类称为基类(或者父类),继承的类称为派生类,子类将获得基类除构造函数和析构函数以外的所有成员。此外,静态类也不能被继承。通过继承,程序可以实现对父类代码的复用。因为子类可以继承父类的所有成员,父类中定义的代码便不需要在子类中重复定义了。
使用了继承之后,当我们初始化一个子类时,除了会调用子类的构造函数之外,同时也会调用基类的构造函数,子类的初始化顺序如下:
1:初始化类的实例字段
2:调用基类的构造函数,若没有基类,调用System.Object的构造函数。
3:调用子类的构造函数。

多态

由于可以继承基类的成员,子类就有了相同的行为,但是有时子类的某些行为需要相互区别。子类需要覆盖父类中的方法来实现子类特有的行为,这就是多态。多态即相同类型的对象调用相同的方法却表现出不同行为的现象。当派生类从基类继承时,它会获得基类的所有方法、字段、属性和事件。面向对象的语言使用虚方法表达多态。若要更改基类的数据和行为,您有两种选择:可以使用新的派生成员替换基成员,或者可以重写虚拟的基成员。

通过接口和抽象类实现多态

实践中,可以通过接口和抽象类实现多态。
如下,多个不同的子类可以通过实现IExtend接口,实现对同一个方法有不同的行为。子类也可以通过override抽象父类的抽象方法从而实现不同的行为。但是可以注意到,我们在调用BasePhone的Video方法,会产生编译报错,即使我们实例化的是一个iPhone,具有Video方法,编译器还是不能读取到该信息,因此我们需要用dynamic关键字避开编译器的检查。

class Program
{
    static void Main(string[] args)
    {
        BasePhone phone = new iPhone();
        phone.System();//运行时多态
        //phone.Video();  编译报错,这是因为编译器的限制;实际在运行时是正确的

        IExtend extend = new iPhone();
        extend.Video();//运行时多态
        //extend.Call()  //


        dynamic dPhone1 = phone; //通过dynamic关键字避开编译器的检查
        dPhone1.Video();


        dynamic dPhone2 = extend;
        dPhone2.Call();
    }
}

public interface IExtend
{
    void Video();
}

public abstract class BasePhone
{
    public void Call()
    {
        Console.WriteLine($"Use {this.GetType().Name} Call");
    }

    public abstract void System();
}

public class iPhone : BasePhone, IExtend
{
    public void Video()
    {
        Console.WriteLine($"{this.GetType().Name} Video");
    }
    public override void System()
    {
        Console.WriteLine($"{this.GetType().Name} System is IOS");
    }
}

public class Mi : BasePhone, IExtend
{
    public void Video()
    {
        Console.WriteLine($"{this.GetType().Name} Video");
    }
    public override void System()
    {
        Console.WriteLine($"{this.GetType().Name} System is Android");
    }
}

那么,在实践过程中,如何选择抽象类和接口呢?

我们需要了解抽象类和接口的特点。对于接口而言,是约束,多实现,更加灵活,语义方面有点像:can do,可以说“实现接口的子类 can do 接口约束”。抽象类 是父类+约束,可完成通用的实现,只能单继承,语义方面有点像: is a,可以说“子类is a 父类”。
因此,有的子类有,有的子类没有的情况,就要考虑用接口。
选择接口还是抽象类的原则:子类都一样的,放在父类;子类都有但是不同,放在父类抽象一下;有的子类有,有的子类没有,那就用接口。
一般情况,接口用的更多,因为接口更简单灵活 除非有些共有的需要继承。

抽象方法和虚方法的区别和选择?

最本质的区别:虚方法带有实现(方法体),可以被重写;抽象方法没有实现,必须被重写(override)。
在实践中,虚方法,抽象方法在继承中的行为也不同,如下所示。

class Program
{
    static void Main(string[] args)
    {
        //虚方法/抽象方法,程序编译时候,左边遇到virtual/abstract时,做个标记,等程序运行的时候,判断右边是否有override,如果有,就以右边为准

        ParentClass parent = new Child();
        parent.CommonMethod();//普通方法,父类为准;这个是编译时确定的,特点是:效率高
        parent.VirtualMethod1();//虚方法,子类没重载,左边为准
        parent.VirtualMethod2();//虚方法,子类有重载,右边为准;运行时确定,特点是为了灵活
        parent.AbstractMethod();//抽象方法,右边为准;运行时确定,特点是为了灵活
        Console.Read();
    }
}
public class Child : ParentClass
{
    public override void VirtualMethod2()//子类重载了父类的 VirtualMethod2
    {
        Console.WriteLine("我是子类,重载虚方法2");
    }
    public sealed override void AbstractMethod() //sealed保证子类不能再重写该方法
    {
        Console.WriteLine("我是子类,实现后的抽象方法");
    }
}
public abstract class ParentClass
{
    /// <summary>
    /// 普通父类方法
    /// </summary>
    public void CommonMethod()
    {
        Console.WriteLine("我是父类,普通方法");
    }
    /// <summary>
    /// 父类虚方法,必须包含实现,可以被重载
    /// </summary>
    public  virtual void VirtualMethod1()
    {
        Console.WriteLine("我是父类,虚方法1");
    }
    public virtual void VirtualMethod2()
    {
        Console.WriteLine("我是父类,虚方法2");
    }
    /// <summary>
    /// 我是抽象方法
    /// </summary>
    public abstract void AbstractMethod();
}


参考:
面向对象详解
C#面向对象基本概念总结

posted @ 2020-11-23 21:17  Jamest  阅读(191)  评论(0编辑  收藏  举报