重读TIJ中对象导论一章

     关于面向对象,一直都没有静下心来做一个好好的总结。读过很多书,对于OO的说法有很多的共同点,也有一些差异性。现在试着总结这些共同点。

      一、抽象过程。

      OO的优点是,可以把问题空间很自然的描述出来,然后基于这个问题空间编织成解空间。因为太简单了,习惯用语言来直接描述解空间的程序员都觉得难以适应。

      Smalltalk的作者Alan Kay总结过纯粹的面向对象程序设计方式的五个基本特性:

      (1)、 万物皆为对象。

      (2)、程序是对象的集合,他们通过发送消息来告知彼此所要做的。消息即为互相调用的请求。

      (3)、每个对象都有自己的由其他对象所构成的存储。

      (4)、每个对象都有类型。类型最重要的特征,是”可以发送什么样的消息给它“。即对象的接口。

      (5)、 某一特定类型的所有对象都可以接收同样的消息。可替代性是OOP最重要的概念之一。

扫描二维码关注公众号,回复: 1330171 查看本文章

      根据Booch的描述,对象具有状态(内部的数据)、行为(方法)和标识(在内存上有惟一的地址,在分布式对象中还有其它的辅助信息)。

     

       根据我的理解, 类就是依靠消息通信为生,拥有数据成员和操作成员的复合抽象数据类型。对象就是它的实例。

    二、如何设计良好的对象?

    我们都知道AUP中有领域建模,要把系统分解成各种各样的类。怎样把系统分解得最好?

    天然的类,都自发地是某些服务的内聚。我们可以根据服务来划分类。这样的内聚性会很高。

    三、隐藏具体实现。

      程序员可以分为两类,类创建者(即设计类库的程序员)和客户端程序员(即类消费者)。我们在修改一个语言类库的时候属于前者,平时编程复用类库中的类的时候属于后者。两者之间有一条很多边界,类应该只暴露必须的部分而隐藏其他必须的部分给类消费者。

      原因有二:

      (1)、不要让客户端程序员触及他们不该触及的部分,避免他们不当的更改引发新的问题。

      (2)、允许设计者改变类的内部工作方式而不用担心影响到客户端程序员。

       四种访问权限:

       public 完全公开,谁都可以访问。

       protected 在类族内公开,继承下来的类也都可以访问,同样也在包内公开。

       default 在包内公开,包内的其他类可以访问。

       private 只在本类内公开。包括内部方法和内部类。

    四、 复用具体实现。

      如果一个类的成员是类,那么两个类之间的关系属于composition(组合)。如果这种组合是动态发生的,就可以被称为aggression(聚合)。最好把这些成员声明为private的,这就可以不被外在的其他成员干扰。这是一种has-a关系。

    五、继承。

      子类继承父类,可以很简单地复用父类的属性和行为(实际上是引用问题空间的一种设计),带来了很多便利。但是很多时候这样是不足够的,我们还可以通过更多的方式来拓展它。

      (1)、直接添加新的成员,但是在父类中却不可以引用。它变成了一个is-like-a的关系。不再是纯粹的原类型,上转型就必然窄化,意味着上转型时不可使用新方法。如果把它移动到父类中,又有可能带来问题繁衍(problem propagation)。要慎用。

      (2)、extends,即扩展。就是要用overriding。这样即使上转型也可以很自然地工作没有任何问题。它仍然保留着is-a 的关系。

     六、伴随多态的客户换对象。

     编写不依赖特定类型的而依赖于某个设计类型的代码,是多态造成的,也是面向对象的魅力。它有两个特点:

     一、不依赖特定实现类型的设计类型。

     二、对象可以根据自己的具体类型执行特定的代码。后面这一点即要求运行时多态,动态绑定。C++中默认关闭,需要使用virtual关键字打开。Java中默认打开了。无法使用多态的,非面向对象编程编译器,例如C编译器,编译时很容易就产生函数的绝对地址。

    七、单根的继承结构。

      在OOP中,自C++面试依赖就已经变得非常瞩目的一个问题就是,是否所有的类最终都继承自单一的基类。在Java中(实际上是在除C++以外的所有的OOP中),答案是yes。

     为什么C++选择使用多根继承?为了受限较少地向C兼容。无法确保所有的对象都出自同一个基本类型。因为历史原因,获得的类库中总有很多不兼容的接口,这就需要多重继承来让这些设计融合。

     但如果是一些刚刚从头开始的语言,可以从零开始编写它的类库。则使用单根继承结构就可以带来巨大的OOP便利,这些便利在大量的OOP语言中都可以看到。

     单根继承结构的好处至少有:

     1 所有类型都有一些基本的操作,如hash(),equals()。

     2 所有对象都很容易在堆上面创建。(为什么?)

     3 参数传递可以得到极大的简化(即所有的对象都可以声明为Object的对象,而不必担心不能上转型成功。在没有泛型的时代,这是Java折中的一个方法)。

    八、容器。

      当我们不知道解决某个特定问题需要多少个对象时,我们需要一些特殊的对象类型,即容器。容器优于一般的数组类型的地方是它们可以增加很多自定义的操作。真正需要的是一个可以被操作的解决问题的序列。

      对容器是有所选择的,因为,

     (1)、不同的容器提供了不同的接口和外部行为。

     (2)、不同的容器对于不同的行为有不同的效率。

    九、参数化类型。

      旧有的Java中,Object容器类型是无参数化的,上转型的时候还没什么,但下转型几乎可以肯定是不安全的,很容易报运行时异常。为了避免这个问题,要刻意留心做检查,并且要手动转型。这样会浪费程序员很多很多心血。所以提出了一种解决方案,即参数化类型,参数化类型可以很好地自动化交由编译器(而不是虚拟机)对类型进行检查和自动转化。

     Java中的参数化类型成为范型(此处可能有笔误,泛型?)。

    十、对象的创建与生命周期。

    在C++中,如果预先知道对象确切的数量、生命周期和类型,则可以使用一些技巧将对象安置于堆栈中(称之为自动变量或限域变量)。但是这是怎么做到的呢?纯粹调用构造函数而不使用new关键字?

    但更常见的做法是在堆上创建和销毁对象。堆是一块可以任意裁剪的内存池。因为是运行时动态管理的,不能自动被编译器指令所控制(往往只需要编译器加入一条或数条汇编指令,压栈、保留原栈底指针且移动栈顶指针),所以在队中分配存储空间实际上比在堆栈上慢得多,依赖于存储机制的设计(实际上依赖于malloc()函数或者new运算符的具体实现)。

猜你喜欢

转载自cppbomb.iteye.com/blog/1603337
今日推荐