封装

122 阅读6分钟

封装 Encapsulation

面向对象在问题域中的分析与设计(简单版)

1、在问题域当中寻找名词;

我们找到的名词有两种情况:

一个是在Java语言当中,没有现成数据类型表示的,那么就是需要我们去自定义的类(类型);

一个是可以在Java语言当中找到数据类型来表示的名词,那么它们通常都应该是某个我们自定义类的属性。

名词:

用户、用户名、密码、钱(余额、ATM机当中存放的现金)、ATM机

自定义 String String double   int       自定义类型

2、把找到的属性归纳到它所属的类当中去

用户: 用户名、密码、余额;

ATM机: 现金、最大现金数、最小现金数

3、分析类与类之间(对象与对象之间)的关联关系

用户、ATM

用户 use - a ATM - 不合理

ATM has - a 用户 - 正确

为什么采用第二种关联关系来设计呢?

因为,这里的用户不是指在现实世界当中的一个具体的生物性的人,而是这个人在银行系统中的数据映射。这里的用户其实是指在银行系统中存放的用户信息。

4、分析动词,动词就是行为

登陆、注销、选择菜单、查看余额、存款、取款、转账、修改密码、退出

然后关注这些行为是设计在哪个类当中的?

这些功能在本问题域当中应该都定义在ATM机上,因为谁提供这些功能就应该定义在谁身上,用户只是调用这些功能,ATM才是功能的提供者,所以功能的定义是放在机器上面的。更何况,上面3的分析已经指出本问题域当中的用户只是数据而已,所以应该是ATM提供功能操作用户数据。

5、现在在简单问题域当中,我们已经可以用代码表示出基本类结构了

如果是在复杂问题域(比如以后你们要做的大一点的项目),那么我们就可以使用设计工具进行进一步的图形化设计了(比如:类图、流程图等等)。

在定义代码的基本结构的时候,类的定义和属性的定义后好办,关键是方法的定义(特别是方法的返回和参数)。在定义方法的返回和参数的时候一定要确认方法在哪里被调用。

6、设计结束以后,然后再挨个开发每一个功能模块。

切记不要一次性实现完,而是实现一个测试一个,保证每个模块的正确性。

面向对象和面向过程的对比

面向对象最大的特点就是分析的过程不再采用解决问题的步骤作为分析的切入点,而是换成分析问题域中参与的角色作为切入点。

它主要针对的是大型问题域,由于过程复杂,数据的交互比较繁琐,所以必须有这么一个分析过程,去整理清楚角色、角色职责和角色的关系。

常见面试问题:

面向过程和面向对象谁好?或者说谁更符合人类的自然思维?

在我的观点来看,这个问题是一个比较性的问题,而不是得出谁比谁好,应该是在某个问题域当中谁比谁更自然一点。

  1. 两者都是符合人类自然思维的;只不过这个自然性是表现在不同情况下,当一个人解决他熟悉或他能够控制的问题域的时候,他的自然思维必然是面向过程的;但是当一个人遇到他不熟悉的问题域,那么他是不可能整理出步骤的,所以他只有先去认识整个问题域。而认识整个问题域的方式呢?最自然的就是分部件(分工)去认识里面每一个参与角色。
  2. 面向对象不可能替换掉面向过程;面向对象更大的优势在于分析陌生问题域,然后搭建开发人员的认知结构和代码结构,但是一旦到了具体实现的时候,还是需要一定过程性的思维,至少每个方法的实现还是有过程性的表现呀。
  3. 以后的学习过程中,我们还会遇到其他的面向(比如:面向接口,面向切面等等),它们其实是在特殊问题域中站在另一个角度去分析看待问题域。

面向对象四大特征 --- 封装

封装、继承、多态、抽象

我们在前面学习到的类的定义,访问修饰符这些都属于面向对象当中“封装”这个特性。 在我们前面学习的“类”的定义,其本质就是在学习封装当中“装”的这个过程。我们把我们在系统当中所需要用到的数据和功能进行分门别类的放置,有些设计在A类,有些在B类当中。我们可以认为“类定义”当中的那对“{ }”其实就是我们装的边界。

包的引入其实也是一个“装”的体现。一个包里面的类理论上只能直接认识本包中的其他类,来自于其他包的类必须使用 “import 告知”。我们在写一个类的时候,不需要用import来告知的是什么呢?

  1. 来自于java.lang包中JDK类;
  2. 自定义于本包中的类。
  3. 有一种特殊情况,我们要在自定义类中使用多个需要import进来的同名类,咋办呢?

多个同类型的对象如何处理? --- 我们把它们可以装到一个集合中去。

而集合大家目前只学习过一种,叫做数组。这里,对象也可以放到数组中去。

数组的产生语法证明了数组本身就是一个对象,它是存在内存的“堆”当中的。比如: int[] sum = new int[10]; 我们可以看成sum 指向了一个对象,该对象有10个int类型的属性用来装数据,默认初始化为0。只不过,我们没有给这10个属性命名,所以它只能用编号"0-9"来表示。而且所有的数组除了装数据的属性,至少还有一个公共属性叫“length”,所以我们访问数组长度的语法“数组名.length”。

面试中,经常有两个词汇,“基本数据类型数组”和“引用数据类型数组”。大家要注意认知清楚:

  1. 数组一定是引用数据类型;
  2. “基本数据类型数组”是指数组中的元素是基本数据类型;“引用数据类型数组”是指数组中的元素是引用数据类型。

面试的时候遇到“封装”的问题,要注意:

  1. 封装不仅仅只是“封”,还包括“装”的方面;
  2. “封”也不仅仅是信息的隐藏(数据的隐藏),还包括方法的具体实现的隐藏。方法本身就是把实现细节进行“封”的实现,让外部的调用者看不到具体的实现(对于外部调用者来说用就可以了)。