测量小百科 | 面向对象的编程方法(一)
来源: | 作者:JYTEK | 发布时间: 2020-07-09 | 767 次浏览 | 分享到:
全文字数3322 | 阅读需要4分钟


关键词:编程、面向对象、C#、.NET、OOP

导读

目前的编程世界中有很多种编程语言,例如常见的C/C++、JAVA、C#、Python、javascript等,每种语言都蕴含着代码设计者对于软件设计的思想,这些思想是在解决软件开发问题时常用设计的抽象归纳。面向对象是目前主流语言中都比较常见的一种编程思想,在本文中将简单给大家介绍关于面向对象的相关概念及面向对象思想下设计软件的常用方法。


目前主流的编程思想

数据和行为是编程中最核心的两个元素,不同的语言在这两个元素的组织形式上不尽相同,其中面向过程、面向对象、函数式编程是该范畴下常见的三个范式,目前主流的编程语言设计大多是基于这三个思想中的一个或多个。

面向过程:一种以过程为中心的编程思想,该编程范式关注业务的流程,使用过程组织行为,通过行为操作数据。C语言即是最常见的面向过程的编程语言。

面向对象:以对象为中心,将关联的行为和数据各自组织为有边界的数据结构,以组件-通信的方式组织软件结构。C++、JAVA、C#、Python、JavaScript等都支持面向对象的编程方式。

函数式编程:核心是函数,关注数据的映射,不维护内部状态,将计算过程分解为纯函数,基于计算流程组织结构,常用于线性执行或分布式执行的数值运算、逻辑运算、数据处理等。函数式编程较少独立存在,大多是作为其他编程方式的补充,例如C#、Java、JavaScript在基于面向对象的情况下提供了很多对函数式编程的支持。

除了三个主流的编程范式外还有其他的一些常用的编程泛型,例如命令式编程、声明式编程,本文将不再就此展开。


面向对象的思想和实现类型

面向对象是目前主流语言中常用的一种软件开发思想,该思想提供了一种具有对象概念的程序编程泛型,将编程世界中数据和行为两种关键要素合二为一。面向对象的思想和结构化设计方法非常契合,可以很大程度缩短软件生命周期中从模型抽象到代码实现之间的距离,提高软件开发的效率和代码的质量。

面向对象提供了多种实现方式,最常见的包括:

  • 基于类的面向对象:使用类的方式定义数据与行为的组织模型,通过创建类的实例实现模型的副本,通过副本间的互相调用和通信完成指定功能,核心在于类的定义和实现。该实现方式是目前最常见的面向对象,使用该方式的语言有C#、C++、JAVA、Python等。

  • 基于原型的面向对象:关注分类和类之间关系的开发模型,定义原型提供类的简单定义,关注于各自实例的特殊性和各自实例的行为,允许运行时对原型的修改,核心在于不同的实例。使用该方式的语言有Javascript

本文后面的所有面向对象都特指基于类的面向对象。


面向对象的编程

在编程的过程中实践面向对象的思想即是面向对象的编程(OOP, Object Oriented Programming)。面向对象的编程方法中所有的数据和方法都必须定义在类中。类需要通过实例化创建可访问可执行的对象,通过关联对象之间的调用实现业务流程。

面向对象编程是一种具有对象概念的程序编程范式,同时也是一种程序开发的抽象方针,它可能包含数据、属性、代码与方法,对象则指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的可重用性、灵活性和可扩展性,对象里的程序可以访问及修改对象相关联的数据。在面向对象编程里,计算机程序会被设计成彼此相关的对象。

面向对象程序设计可以看作一种在程序中包含各种独立而又互相调用的对象的思想,这与传统的思想刚好相反:传统的程序设计主张将程序看作一系列函数的集合,或者直接就是一系列对计算机下达的指令。面向对象程序设计中的每一个对象都应该能够接受数据、处理数据并将数据传达给其它对象,因此它们都可以被看作一个小型的“机器”,即对象。

面向对象有三大特性:封装实现数据和行为作用域的管理;继承实现数据和行为的逻辑包含;多态实现运行时对逻辑上有关联的对象的动态引用。该章节以下就分别对这三个特性进行介绍。


封装

封装是将关联的数据和行为封装到模板(类)中的操作,让每一个类只负责和当前类业务相关的工作,将业务的复杂度分解并下放到每个业务模块,隐藏实现的细节,对外只开放最简洁的业务接口。未使用封装和使用封装后代码的结构对比如下图所示


在.NET面向对象的实现中,类主要包括以下几个部分的定义:

  • 构造方法:定义使用指定参数创建对应类实例的方法。该方法名与类名相同。

  • 字段:定义类中的数据,字段定义数据的物理存在,在内存中有指定的引用。字段原则上应定义为私有,即只有类内部可以访问。

  • 属性:定义类中对外的数据接口,该数据接口的访问权限可以标记为只读或可读可写,属性关联的数据可以来源于某个字段或者返回对应数据的方法。

  • 方法:定义该类中应该实现的行为,可以访问的数据包括方法的入参、当前对象的所有字段/属性/方法、其他可访问对象及其公共属性/方法。

  • 同时.NET对所有的类和属性/方法/字段都提供了访问权限的控制,从开放到封闭分别用以下关键字声明:

  • public:公共访问类型,所有代码都可以访问该属性/字段/方法。

  • internal:内部访问类型,当前程序集内的所有代码可以访问该属性/字段/方法。

  • protected:保护访问类型,当前类和当前类的所有子类内部可以访问该属性/字段/方法。

  • private:私有访问类型,仅当前类内部的代码可以访问该属性/字段/方法。

属性/字段/方法的获取和调用都必须通过类的实例(除了使用static修饰的属性/字段/方法),常见的使用一个实例类的过程为:使用new调用某个类的构造方法创建该类的实例,将返回的类实例传递给变量;使用变量操作该实例的所有属性/字段/方法。如果某个类型的实例在执行构造方法初始化以前访问实例的实例属性/实例字段/方实例法,运行时将会抛出空指针类型的异常:NullReferenceException。

.NET中支持的封装类型主要包括实例类、静态类、抽象类、接口等,关于这部分的详细资料参见MSDN的相关链接:https://docs.microsoft.com/en-us/dotnet/csharp/。

继承

继承分为两种:类继承、接口实现。

类继承可以实现类之间对公共数据和公共方法的共享,实现逻辑上的包含关系,即某个类是其父类的一种特例(例如猴子类(子类)是动物类(父类)的一种)。子类和父类的关系如下图所示,子类在对外的接口中既包含自身定义的属性2和方法2,同时也包含了父类的属性1方法1


接口是对特定功能的抽象,即通过接口可以定义实现某个功能必须具备的方法,该方法的描述仅关心对外交互的接口而不关心具体的实现。类可以显式的声明实现了某个接口,实现指定接口的类在逻辑上即具备该接口的功能。实现接口代表某个类(接口实现类)具备某个功能(接口)。计算机实现USB接口即计算机具备使用USB传输数据的功能。例如下图中声明接口ISerializable,定义了可序列化对象的对外接口,该接口定义了一个GetObject方法。类1、类2、类3实现了ISerializable方法,所以类1、类2、类3都具备了序列化的功能,每个类中对GetObject方法的实现可能不尽相同。接口中可以定义实例属性(属性本质上对应get和set方法)、实例方法,不支持对实例字段的定义(因为字段定义需要涉及内存分配,而接口只描述接口,不负责实现)。



多态

多态是基于继承以上的特性,多态是指对某个类实例可以被传递给以其父类或接口的定义的对象,同时使用该对象对其父类或接口的属性、方法的调用最终会被引用到这个实例的实现。一个关于多态的简要说明如下图所示,Class1、Class2、Class3继承了BaseClass,且各自实现了BaseClassfunc方法,Class1、Class2、Class3的实例可以被赋值到BaseClass类型的变量classInst,使用classInst调用func方法,该调用最终引用的是Class1、Class2、Class3中实现的func而非BaseClass中的func


多态是面向对象编程的灵魂所在,多态可以将相同功能的不同实现巧妙的隐藏起来,对外只维持最简洁的接口,将业务中变化的部分巧妙的隔离到业务逻辑的设计之外,很大程度简化应用的开发、提升软件工程的可维护性。

封装、继承、多态三个特性之间是层层递进的关系。封装通过类提供最基础的数据和行为绑定,实现功能接口定义的机制(interface)、继承实现类之间的逻辑包含关系、多态用来处理存在逻辑关系的对象之间的调用问题。



参考

  1. 面向对象编程

  2. 编程范式游记

  3. 编程范式(Programming paradigm)

  4. Inheritance in C# and .NET

  5. C# language specification