论坛首页 Java企业应用论坛

从Domain Object引出的OO对象和OO语言的关系

浏览 2334 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-10-05  
OO
曾经有一段时间,论坛上对于Domain Object的实现争论不已,这包括:

1. 再次小结领域模型的种种观点:
http://www.iteye.com/topic/17579

2. 总结一下最近关于domain object以及相关的讨论
http://www.iteye.com/topic/11712

另外,robbin还在下面的帖子中提出 [Hibernate实体类 != 领域模型]
http://www.iteye.com/topic/11608

其实Domain Object不是一个语言层面的概念,因而如果拿它来对应于实现层面的某一个类,那么很多时候你是无法对应上去的。也就是说,在实现的层面,有的时候你需要多个类或者一个包来实现所谓的Domain Object。如果从这个思路来看,关于Domain Object的实现是应该是贫血模型、失血模型还是充血模型之间的区别也就并不是那么大了,其实本质是你用一个类还是多个类去实现Domain Object,并且向外提供一个接口还是多个接口访问Domain Object的问题。

从这个问题我想到了关于OO中对象和OOP中对象的区别。其实我们很多人对OO中的对象的概念的理解来源于OOP,而不是OO思想本身,而正是这种把OOP的对象当做OO对象的方式制约了我们对OO的理解。

简单的说,OO思想起源于软件设计的一些基本方法,其中最重要的就是模块化、封装和信息隐蔽,这些方法导致了对象的概念,就是封装数据和行为,另外重用方法导致对象的继承概念,而另外的一些概念如多态,接口则完全是某些语言的特性(如静态语言有多态的概念,而对动态语言则不需要),而非OO本身的特性。所以说,从本质上来说,OO中的对象就是对数据和行为的封装。

我们再来看OOP,其实OOP中的所谓的类是对OO中的对象的一种实现,它和OO中的类并不是完全一一对应的关系。同样我们可以使用非OOP语言来实现OO中的对象,只要我们能够很好的对对象的数据和行为做很好的封装。只是一般来说,使用OOP语言进行封装比使用非OOP语言进行封装要容易的多而已。

我个人觉得,OO中的对象和语言实现之间有这么几种关系:
1.  OO中的对象不一定和OOP中的对象一一对应,很多时候需要一组OOP中的对象来实现OO中的对象。

2.  用任何语言实现OO中的对象,单靠语言本身的特性是不完整的,还需要在语言之外进行特定的约定,即使对于OOP也是如此。

3.  对于传统的非OOP语言,通过增加一些约定,也可以实现OO中的对象。

对于第一点,上面所说的Domain Object就是一个典型的例子。

对于第二点,我们来举一个不是很恰当的例子来说明:
public class Rectangle {
    private int width;
    private int height;

    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public int getWidth() {
        return width;
    }
    
    public int getHeight() {
        return height;
    }

    public int getArea() {
        return width * height;
    }
}


表明上看,这个类对面积的计算封装很好,其他类只能通过该类的public方法进行访问,但是如果我们对该类的用法没有很好的约定,那么如果其他的类中充斥着这样的代码你会怎么想:

int area = rect.getWidth() * rect.getHeight();


显然,由于没有很好的约定,使用者破坏了对面积计算的封装特性,如果有一天你要改变面积的计算方法(当然这是不可能的,所以说这时一个不恰当的例子)的话,你将无能为力。当然,如果你在事先约定所以计算面积的方法都必须使用getArea方法就可以避免破坏封装的情况。

再看第三点,这里有一个非常典型的例子。使用过C语言的人一定都知道进行文件操作的时候我们使用标准IO库(stdio.h),而操作这些文件我们一般需要FILE结构和一些API,如fopen,fclose,fread,fwrite,其实单从封装的角度来说,FILE结构和这些函数就是典型的OO中的对象。通过俗称的约定,没有人会去直接操纵FILE结构中的成员(实际上,很少有人去看这个结构中究竟有什么内容),这就是所谓的数据封装,另外没有人关系那些函数的实现,这就是行为的封装。它们和一般的OOP之间的区别只是形式上的,用fopen来创建FILE对象,而不是new,用fclose对象来销毁FILE对象,而不是delete,用传入FILE指针作为参数来调用方法,而不是通过"."或者"->"。

总之一句话,OO中的对象可以通过各种方式来实现,可以使用OOP中的类,也可以使用OOP中的多个类,甚至可以不使用OOP中的特性(如果不使用extends的方式来实现继承),另外通过语言来实现的对象的封装是不完备的,你需要使用额外的约定。
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics