在面向对象方法中的众多原则实际上都是为了方便实现目标而设定的,基本上分为三种情况:
一个是模式化,也就是固定的一种约束。例如屏幕的分辨率、必须要有的基础功能,等等。
二一个就是抽象化,遇到抽象这个术语的时候,许多学生都会一头雾水。到底什么是抽象?简单来说就是一种理论性的说辞,例如:设计图。
最后就是封装了,封装地理解也容易,比如一台组装好的电脑就属于一种封装概念。在用户使用电脑的时候只需要按下电源就可以启动系统,等待进入桌面界面。
在每个领域都会有各自的术语,理解其实际意思是关键,这对于新生来说是首要任务。当然沟通中使用术语是要分对象的,不是你知道了术语就可以随便到处使用,反而会影响沟通。那么下面就分别解释一下这三个原则:
第一模式化原则:
如今的许多软件或系统都包含了许多不同的组件,组件之间也都要正确地进行互动,这样才能保证整体系统的有效性。要想维护好这些交互活动,最直接的方式就是良好地把这些互不相同的组件组织在一起。
模式化虽然看起来死板,但是这要注意每种模式都是用在具体环境中的,不能一刀切地去套用。组织的原则就是要把不同的组件分解成独立的功能单元!
就像我们所住的房子一样,不同的空间具有不同的功用,客厅、卧室、厨房、餐厅、卫生间。所以模块就成了软件中每个房间一样,来保留自己的特有功用。不同模块之间提供的功能也要彼此区分开来,没有重复的,这样才具备可管理性。
常说的单元测试就是针对一个模块来进行的。在 Python 中我们会看到模块就是最好的一种组织函数和类的单元。在 Python 标准库中也是如此进行组织的,例如 math 模块、os 模块等等。
那么模式化原则的作用是什么呢?就是给设计目标提供支持,目前对于软件的健壮需求越来越普遍化,因为更容易把测试和调试分离开来去开展工作,这样在满足质量需求后才进行集成到其它软件系统中。
进一步说在一个完整的系统中 bug 是要能够被追踪的,而且知道 bug 来自哪个具体的组件,这样在修复 bug 的时候才不会影响其它组件。
模式化所使用的组织结构也会提升软件的复用性。如果软件中的许多模块都采用通用方法来书写的话,那么这些模块就可以用在其它环境中。尤其是在数据结构相关的领域,通常会设计成足够抽象,且让普通人都能理解使用的形式。
第二抽象原则:
抽象这个术语理解起来其实很容易,因为换一个意思的表达就是提取的意思。在实际中要解决的问题是把一个复杂的系统分解成最基本的几个部分。通常描述一个系统的各个部分都要通过名字就可以达到让人顾名思义的效果,然后解释其中的实际细节,包含对功能的描述。
采用抽象流程来设计数据结构那就需要 ADT 内容了。一个 ADT 就是一项数据结构的数学模型,描述时要说清楚数据存储的类型是什么,所支持的数据操作有哪些,以及操作时包含了那些参数类型。
对于描述一个 ADT 时要说的话是解释每一个操作干了什么,而不是说一个操作是怎么做到的。我们常常会指向许多行为集合,这些行为表现都是由 ADT 来支持才能实现的,作为一种公开的接口。
对于 Python 这种编程语言来说,提供了很棒的操作范围,接口的描述容易实现。Python 有一项隐含的处理抽象传统做法,那就是使用众所周知的鸭子类型理论,因此 Python 成为了一种解释型动态编程语言。
意思就是在检查数据类型时,在 Python 中是没有编译耗时的。不像静态类语言,不强迫你写出声明抽象基类的代码。所以 Python 程序员都会知道一个对象支持一些默认行为,如果假设操作失败的话,解释器会抛出一项运行错误。
鸭子类型理论是 James Whitcomb Riley 诗人发明的,其含义是人的局限性在于只能通过对象的外表行为来判断对与错。至于原文如果你们感兴趣可以自己搜索一番。
更正式地来说,Python 支持的抽象数据类型就是使用了 ABC 来实现的。(abc 是 abstract base class 英文首字母缩写形式。)
一个抽象基类是不能够完成实例化的,意思就是你不能用抽象基类来建立一个实例对象。但是抽象基类的作用是,它负责定义一个或多个共同的方法,而这些方法必须写在抽象基类中。一个 ABC 类的实现也是通过具体写一个类,而这个有形的类是需要继承自抽象基类,同时要部署 ABC 中声明的方法。
Python 中的 abc 模块为 ABC 提供了正式的支持,尽管我们自己不用写那些声明代码,但内部还是需要的,这样的意义在于简化了建立抽象基类的书写。
第三封装原则:
在面向对象设计中另一个重要的原则就是封装了。一款软件系统中存在着许多不同的组件,这些组件各自的实现细节是隐藏起来的。这样做的好处是让一名程序员具有创造性地去部署一个组件的细节,而不用担心其他使用组件的程序员会破坏组件的内部工作原理。
那么有好就有坏,封装的坏处就是提升了软件维护的成本,不管这个组件具备公开的接口还是隐私接口,维护从此就会变得麻烦起来。因为其他使用组件的程序员必须遵循组件提供的接口规则来写代码。
封装会带来健壮和适应性问题,对于允许部署一个程序组件的细节来说,要更新组件就会在授权下才可以实施,因为会影响到其它部分。同时对于修复 bug 来说实际上会更容易,增加新的功能也都是在本地范围里进行变更就可以更新一个组件。
Python 在对待封装这种原则时,采用了松散式管理,也就是说 Python 内部会自动生成相关文档内容,不管你命名时采用什么样的风格,会自动形成一种惯例,那就是公开命名与非公开命名方法。