1 抽象化
编程语言都是实际问题的抽象。而问题的复杂性取决于抽象的类型和质量。
程序可以通过添加新的对象使自身更适用于某特定问题。因此阅读代码其实也就是在阅读问题的描述。
在程序执行期间具有不同的状态而其他方面都相似的对象会被分组到对象的类中,这就是 class 关键字的由来。
类描述了具有相同特性(数据元素)和行为(功能)的对象集合,所以类其实就是一个数据类型。
任何程序都是所设计系统的一种仿真,OOP 就能将大量问题降解为很简单的解决方案。
但是 OOP 的挑战之一就是建立问题空间的元素和解空间之间的对象的一一映射。
这必须有某种方式可以产生对对象的请求,通知它去完成所需任务。每个对象只能满足某些特定的请求,而这些请求呢?就由接口所定义,决定接口的是类型。
接口确定了对某特定对象所能发出的请求。
将对象看做服务的提供者,程序本身就是向调用者提供服务的,而 app 就是通过调用其他对象所能提供的服务来实现这一目的。
不要妄图一个对象满足了你所有想象,这么多功能对于一个对象来说太多了,对象内部关系复杂之后也将使得 SE 们也难以理清关系,就像一个文件写了几千行,真是吐了!
每个对象都该有其所能提供服务的内聚的集合。优秀的 OOP 设计,每个对象都能很好做好一件事,而不是想着同时做好很多事,那样在现实中往往是同时很多事都做不好。
SE 分为类创建(负责创建新的数据类型)和客户端程序员(只管在其应用中使用数据类型的类消费者)。
类创建者可以隐藏对象内部脆弱部分,不让其被客户端程序员访问到,这至少很大程度上能减少 bug
比如说为了上线某功能,先简单实现,之后有问题再继续升级,而无需一开始就考虑地面面俱到(谁会预料到客户会干出啥莫名其妙之事呢)。
复用性的操作难度很难控制,需要大量经验,但不可否认好的复用性是 OOP 设计的奇妙之处。
最简单复用 - 直接使用该类的一个对象,也可将那个类的一个对象置于其他某个新的类中(比如 HashSet 直接复用 HashMap 成员对象),这便是组合(动态发生的组合称为聚合),一种 has - a 关系。
组合有着极大灵活性,是继承所不能比的。成员对象通常 private 保证私密性,,不会干扰客户端代码,还能动态修改组合对象,以实现动态修改程序的行为。
建立新类时,优先考虑组合,因为更简单灵活,而且设计更加清晰。当然这也需要大量经验,才能看出何时无可奈何只能选择继承。
创建了一个类后,即使另一个新类与其很相似,还是得重建这个新类。如果能复制现有的类,通过添加修改一顿操作适配成一个新类是不是容易多了?这就是继承。
父类包含了所有子类所共享的特性和行为,表示系统中某些对象的核心概念,子类就用来表示此核心的不同实现方式。
继承现有类型,也就是创造了新的类型。
那么如何可以达到这一目的呢?
设计时,仔细审视,经验老道后应该很容易分辨到底采取哪种方式。