飞道的博客

C#编程篇 第03部分 C#核心——面向对象

287人阅读  评论(0)

第03部分 C#核心——面向对象


前言


0.1 面向过程(POP)

  • “面向过程”(Procedure Oriented)是一种以过程为中心的编程思想。这些都是以什么正在发生为主要目标进行编程,不同于面向对象的是谁在受影响。与面向对象明显的不同就是封装、继承、类。简写为POP。

  • C语言:面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。


0.2 面向数据(DOP)

  • 面向数据主要是指面向数据解析(DOP,Data-oriented parsing),也称为面向数据编程(data-oriented processing),是一种形式主义概率语法的计算语言学

  • 面向数据是更多的是在分析、设计、以及实现过程中,以数据为中中心,跟踪数据流向,从而保证数据流守恒。例如,由某个模块分别流向某些模块。而上述一切的操作都基于维护这些数据的完整性、一致性和有效性。同时在设计类的时候,面向数据的设计,为了体现数据的重要性,一般是在类的开始就定义数据。


0.3 面向对象(OOP)

  • 面向对象(Object Oriented)是软件开发方法,一种编程范式。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库方法、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。

  • 面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。


第一部分:封装性


1> 面向对象

  • 前导:功能与数据分离,使用的建模概念不能直接映射问题域中的对象。不符合人们对现实世界的认知和思维方式。自顶向上的设计方法限制了软件模式的可复用性,降低了开发的效率,当系统的需求变化时,维护和扩展都会变得非常困难。

  • 概念:面向对象工程是一种新兴的程序设计方法,或者是一种新的程序设计规范,其基本思想是使用对象,类,封装,继承,消息等概念来进行程序设计。

  • 面向对象是一种对现实世界的理解和抽象的编程方法,把相关性的数据和方法组织为一个整体来看待,从更高的层次来进行程序开发,更贴近事物的自然运行模式。

  • 优点:

    • 从现实世界中客观存在的事物或对象出发来构造软件系统,并且在系统构造尽可能运用人类的自然思维方式。
    • 可提高代码的复用率,提高开发效率,提高程序的可拓展性,清晰的逻辑关系。
    • 对于描述的对象而言,属性是描述对象的静态特征,操作是描述对象的动态特征。
  • 特征:

    • 封装性:把对象的属性和操作结合成一个独立的相同单位,并尽可能隐藏对象的内部细节(用程序语言来描述对象)。
    • 继承性:在泛化关系中特殊类可自动拥有一般类的属性和操作,这叫做继承,而特殊类可以定义自己的属性和操作;对于一般类的功能进行补充(子类复用封装对象的代码)。
    • 继承具有传递性,派生可享受各级基类所提供的服务,从而实现高度的可复用性,当基类的某项功能发生变化时,对它的修改会自动反映到各个派生类,提高软件的可维护性。
    • 多态性:指同一事物在不同条件下可以表现不同的形态。

2> 类和对象

  • 面向对象中类的作用,类是面向对象技术中最重要的结构,支持信息隐藏和封装,支持对抽象数据类型的实现,信息隐藏(对象私有信息)不能由外界直接访问,而只能通过该对象公开的操作来间接访问,有助于提高程序的可靠性和安全性。

  • 基本概念:具有相同的特征,具有相同行为,是一类事物的抽象,可以通过类创建出对象。

  • 语法:
    <访问修饰符><修饰符(限定)><class<T>><类名称>:继承列表 where T:约束条件{ 方法体 }

  • 成员:

    • 特征——成员变量
    • 行为——成员方法
    • 保护特征——属性
    • 类型——构造函数和析构函数,索引器,运算符重载,静态成员

3>成员变量

  • 基本规则:声明在类语句块中,用来描述对象的特征,可以是任意变量类型,数量不作限制,且是否赋值根据需求来。类声明作为class成员时,尽量不new()声明,防止栈溢出。

4>成员方法

  • 基本规则:声明在类语句中,用来描述对象的行为的,受到访问修饰符影响。成员方法不作static修饰,必须实例化对象才能访问,相当于该对象执行了该行为。

5>构造和析构

构造函数

  • 构造函数用于对象分配空间,完成初始化工作。
  • 特征:
    • 名称与类名相同,可以重载,任意数目参数,但无返回的概念,主要用于初始化成员变量,new创建类实例的同时分配初始化成员初始值。
    • 系统会默认生成一个无参构造,无特殊需求,一般都是public修饰。
    • 但未声明无参构造时声明了有参构造,会隐藏掉默认的无参构造。

特殊用法:复用构造

  • 当一个构造的函数签名后有复用构造时,会先调用this(参),然后再调用本体构造:
   class A
    {
   
        public int x;
        public A()
        {
   
            Console.Write("6666");
        }
        public A(int x):this()//复用构造
        {
   
            this.x = x;
        }
        static void Main(string[] args)
        {
   
            var a = new A(1);
            Console.Write(a.x);
        }
    }//output:6666  1;

析构函数

  • 但对象脱离其作用域时,系统会默认生成一个无参析构函数(但引用类型的堆内存被回收时,会调用析构函数)

  • 基本语法:

~ClassA(){
       <可选方法体>    }//只有在垃圾回收时,会调用析构函数

6> 成员属性

  • 基本概念:用于保护成员变量,为成员属性的获取和赋值添加逻辑处理解决public,protected,private的局限性,让成员在外部只能获取不能修改,或只写不可读。作用是保护,限定,加密,赋值等作用。

7> 索引器

  • 基本概念:让对象可以像数组一样可以通过索引的方式访问类的成员,是程序更加直观更容易编写。

  • 语法:

    访问修饰符 返回值 this[参数列表] //<可以重载>
      {
   
              getset}
  • 索引器配合switch和泛型类型返回,比较适用于在类中有数组变量时使用,可以方便的访问和逻辑处理。

8> 静态成员

  • 静态成员巨有全局性和唯一性。

  • 基本概念:用static声明的成员叫静态成员,所属于类,为类中所有实例共享,只能从类名点出而不是类实例。

  • 非实例调用静态的特征:

    • 实例成员在程序中给并不是无中生有的,之所以使用对象,变量和函数,都是要在内存中分配内存空间的,实例化成员目的就是分配空间,在程序中生成一个抽象的对象。
    • 而静态成员在程序开始时,就会分配空间,所以我们可以直接使用,且静态成员同程序同生共死,只要使用了静态成员,只有在程序结束时内存空间才会释放。
    • 每一个静态成员都有自己唯一的开辟空间,这使得静态成员具有了唯一性,不可使用实例成员或this调用,且静态方法中不能调用非静态的方法和引用非静态的成员变量。
  • 作用:常用唯一变量的声明,方便别人获取的对象声明。常用的唯一方法声明。

  • 常量与静态变量:const可以被认为是特殊的静态,都是通过类名点出使用,不同在于const必须初始化,不可修改,静态变量可修改。


9> 静态类

  • 用static修饰的类,只能包含静态成员且不能实例化和继承。一般认为是工具类(Math类,Console类),体现出工具的唯一性,一般为public修饰。

  • 静态构造函数:静态类和普通类都可以有,不能使用访问修饰符,不能有参数,且在调用类的时候优先调用一次静态构造,并且只会调用一次。<自动调用>

  • 静态类可用于拓展方法。


10> 拓展方法

  • 基本概念:为现有的非静态变量类型添加新方法。

  • 作用:提高程序的拓展性,不需要在对象中重新写方法。不需要继承来添加方法,为别人封装的类型写额外的方法。

  • 特点:一定是写在静态类中,且是个静态函数。第一个参数为拓展目标,第一个参数用this修饰。

  • 语法:访问修饰符 static 返回值 函数名(this 拓展类名 参数名,参数列表){ 方法体 }

可以声明在任意静态类里。且静态类必须声明在顶级语言内,不可以是嵌套静态类类。

static class B
    {
   
       public static void Func(this int value,int a)
//为int添加了一个拓展方法名为Func的方法
{
   
int Sum = value + a;
Console.WriteLine(Sum  );
}
}
//在其他类中调用时:
class A
    {
   
        int a = 15;
        a.Func(a:15);//output:30
    }
  • 为int拓展了方法,需要一个对象int实例去调用。可以为任何数据类型和自定义类型拓展方法
  • 但拓展方法名与类中实例方法重名时,拓展方法会被隐藏且只会调用自身方法,当方法签名不一致时,也不会形成重载,不可使用拓展方法。

11> 运算符重载

  • 表示让自定义类和结构体能够使用运算符。(operator)

  • 特征:一定是一个公共静态方法,返回值在operator前面,逻辑处理自定义。但是,条件运算符需要成对实现,一个符号可以多个重载,但是不能使用参数修饰符。

  • 基本语法:

public static A operator + (A a1,A a2)
        {
   
            A a = new A();
            a = a1 + a2;
            return a;
        } 

一元运算符只能有一个参数,二元运算符必须有两个参数,相对应的复合运算符会自动实现重载。


12> 内部和分部类

  • 内部类是嵌套类,点出体现亲密关系,访问修饰符作用很大。

  • 分部类(partial)分部声明,增加程序拓展性,分部类可以写在多个脚本文件中,分部类的访问修饰符要一致,且不能有重复成员。

  • 分部方法和分部类规则类似,且要求声明签名必须一致,不可重复声明局部变量。


第二部分:继承性


1> 继承的基本规则

  • 一个类B继承类A,类B会将类A的所有成员,因此类B会有A的所有特征和行为。

  • 特征:单一继承性,传递性马克间接继承父类的父类。子类可与父类同名,成员同名,但是不建议,用new可以覆盖掉父类的同名方法。


2> 里氏替换原则

  • 表示任何父类出现的地方,子类都可以替代;语法上表现在父类容器装子类对象,子类对象包含了父类的所有内容。作用在于,方便进行对象的存储和管理。、

3> 继承中的构造函数

  • 当声明一个子类对象时,先调用父类的构造函数,再执行子类的构造函数,子类继承父类成员,初始化子类对象的同时,会先将父类对象的成员初始化。

  • 父类无参构造很重要,子类可以通过base代表父类,调用父类构造,在子类的构造函数声明中,可以用base显式指定父类的构造调用。

 class A
    {
   
        public A()
        {
   
            Console.WriteLine("这是A的无参构造");
        }
        public A(int a, int b)
        {
   
            Console.WriteLine("这是A的参构造函数");
        }
    }
    class B : A
    {
   
        public B():base(1,2)//指定调用父类的构造函数
        {
   
            Console.WriteLine("这是B的无参构造");
        }
        static void Main(string[] args)
        {
   
            B b = new B();
        }
    }//output:这是A的参构造函数
           // 这是B的无参构造

4> 万物之父和装箱拆箱

  • 万物之父:object是所有类型的基类,它是一个类,利用里氏替换原则,用object容器装所有对象,也可以用来表示不确定对象,作为方法的参数类型。

  • 使用:

      object obj = value;
      if(obj is T){
   obj as T};
          //T1 = obj as T1;

装箱拆箱:装值类型和拆值类型

  • 装:栈类型迁移到堆内存。
  • 拆:堆类型迁移到栈内存。

当不确定类型时可以方便参数的存储和传递,但会增加性能消耗,存在内存迁移。因此要减少太多的拆装箱操作,减少性能的消耗。


5> 密封类

  • 表示使用sealed密封,使之无法被继承。

  • 作用:在面向对象程序设计中,密封类的主要作用就是不允许最底层子类被继承,可以保护程序的规范性,安全性。在框架中的作用很大。


第三部分:多态性

  • 继承同一个父类的多个子类调用相同方法有不同的表现(让同一对象有唯一行为的特征)

1> 多态的实现

  • 编译时多态——函数重载。

运行时多态——vob(virtual override base),抽象方法,接口

  • 利用重写功能使父类子类对象行为统一。

2> vob模式的优势

  • 当继承的子类拥有和父类相同名称的成员时,用new声明可以覆盖隐藏掉父类的同名成员,这时破坏了里氏替换原则,子类无法正常调用父类的完整成员,当访问父类方法时只能通过父类本身的对象去调用。

  • vob原则:重写父类中继承的虚方法,使得里氏替换原则生效,使同一个对象有唯一行为的特征。


3> 抽象类和抽象方法(abstract)

  • 抽象类:不能被实例化的类,可以包含抽象方法,继承其的子类必须能够重写其抽象方法。

  • 抽象方法:抽象方法只能有签名而没有具体的逻辑处理块,且不能用private修饰。


4> 接口(实现多态的第三种方式)

  • 接口是行为的抽象规范,自定义类型,在7.3#接口中不能包含成员变量,只包含方法,属性,索引器,事件。且成员不能有访问修饰符修饰,接口也可以继承接口。

  • 在8.0#开始,接口可以有具体方法,也可以有访问修饰符,但是仍然不可以声明实例字段,静态成员字段可以声明,并在静态构造函数中进行初始化。

  • 接口与抽象方法相同,不可以实例化,但是可以作为容器装子类对象。


5> 密封方法(多态)

  • 使用sealed修饰重写方法,说明此方法标记已完整。使得虚方法,抽象方法不再被重写。

sealed virtual / abstract


第四部分: 面向对象关联内容


1> 命名空间

  • 基本概念:命名空间用来组织和重用代码的,像是一个工具包,类就像一件一件的工具,都是声明在命名空间里的。

  • 不同的命名空间中相互作用使用,需要using引用命名空间或出处(完全限定名称点出)


2> StringBuilder

  • C#内置了一个用于处理字符串的公共类,主要用于解决的问题使修改字符串而不是创建新的字符串对象,需要频繁修改和拼接字符串可以使用StringBuilder可以提升性能,//Using System.Text;
StringBuilder str = new StringBuilder(String.Empty);
//StringBulider存在一个容量的概念,每次增加内容会自动扩容。
     str.Capacity;//容量
     str.Length;//当前长度。
<>: str.Append(string str);
    str.AppendFormat("{0}"0)<>: str.Insert(index,string str);
<>: str.Remove(index,Length/count);
      str.Clear();
<>: str[index]//索引查找
<>: str[index]='char';
<替换>: str.Replace(str,str2);//用str2将str替换
<比较>: str.Equals("str");       
  • 优点:摆脱了字符串只读的局限性。

3> 结构体和类的区别

  • 最大的区别是存储的空间不同,因为结构是值类型,类是引用类型,结构体存在栈中,类存在堆中。

  • 结构值类型,类引用传递。

  • 结构体和类在使用上相似,结构体甚至可以用面向对象的思想来形容一类对象。

  • 结构体具备有面向对象思想中封装的特性,但是它不具备继承和多态的特征,因此大大减少了它的使用频率。

  • 由于结构不具备继承的特点,因此不可以用protected保护修饰。

  • (细节区别)结构体声明变量不能指定初始值,不能声明无参构造,构造函数必须实现所有成员初始化任务,自带默认无参构造,不能声明析构函数,不能被继承,不能static修饰,成员可以,内部不能声明同名变量,同名用于构造函数。

  • (特殊)结构体可以继承接口,接口是行为的抽象。

  • (如何选择结构体或类)当想要继承多态性质可以使用类(玩家,怪物等),当对象是数据的集合时,优先考虑结构体(坐标,怪物重生点,位置等),从值或引用类型赋值时的区别上去考虑,比如经常被赋值的对象,并且改变赋值对象,原对象不能跟着变化时,就用结构体,如坐标,向量旋转。


4> 抽象类和接口的区别

  • 相同点:都可以被继承,都不能直接实例化,都可以包含方法声明,子类必须为其提供实现,都遵循里氏替换原则。

  • 区别:接口中没有构造函数,且类可继承多个接口,类可以有若干个构造函数且只能单一继承,抽象类中还可以有成员变量和声明成员方法,虚方法和静态成员,抽象方法。在7.3#,接口只能声明没有实现的抽象方法,抽象类可以添加访问修饰符,接口中默认为public。

  • 如何选择:表示对象用抽象类,表示行为的拓展用接口。不同的对象拥有共同的行为,我们往往可以使用接口来实现。



转载:https://blog.csdn.net/weixin_52566131/article/details/116425011
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场