从OO封装谈起

在我们熟悉的OO语言中,可以通过private、protected、public等访问控制修饰符将数据 和方法分为内部可见、子类可见、外部可见等不同访问级别。本文从一个较为特别的封装相 关例子出发,讨论封装、类型系统、契约式编程相关话题。我们先从例子开始:

public class Person {
    private int _money;

    public void Change(amount){
        this._money += amount;
    }

    public void Exchange(Person p, int amount) {
        p._money -= amount;
        this._money += amount;
    }
}

基于”没有经过我允许,不许直接动我的钱”的假设,Person类把变量_money 作为private成员,并提供public的Change方法。但有争议的地方在于,在Exchange中我们可 以直接访问并修改p._money。请注意上面的代码在C#编译器下是完全合法的,类似的代码在 C++和Java下也一样。我在第一次接触这个例子的时候,起初有些疑惑编译器是对还是错?后 来想了一个理由“OO的封装是基于类的,而非对象”来说服自己。

现在,对这个问题有了更新的认识,希望和大家讨论。上面的例子中,我们的理想情况是 Person对象本身可以直接访问自己的_money变量,其他Person对象不能直接访问。但OO的封 装实现必须依赖编译器进行静态访问权限检查;既然是静态那就只能应用到类型,无法应用 到对象实例。因此,在上例中C#编译器无法确认p和this是否引用同一对象或不同对象。从这 个意义上讲,OO的封装只到类这一级别与其说是设计考虑不如说是不得以的选择。

从更大的层面上讲,这个例子不仅和OO封装相关,本质上是反映了程序语言类型系统的作 用和局限。程序语言的类型系统是一种静态的跟踪和检查机制,它能保证程序的类型正确性 ,但无法保证语义正确性(理想情况下,上面的例子中,p如果和this是同一对象那么语义正 确;否则,语义错误)。换句话说,类型正确性可以通过类型系统用形式化的方式进行表达 和检查。那么语义正确性应该如何来保证呢?有没有形式化的方式呢?答案也许就像下面这 样:

public class Person {
    private int _money;

    public void Change(amount){
        this._money += amount;
    }

    public void Exchange(Person p, int amount) {
        Assert(this != p);
        p.Change(-amount);
        this._money += amount;
    }
}

增加Assert断言,就是希望从形式上保证语义的正确性。我的理解是:我们需要一种形式 化的方式保证语义的正确性。这是不是就是所谓契约式编程的初衷呢?希望高手指点!

时间: 2024-10-14 22:54:54

从OO封装谈起的相关文章

深一层看依赖注入

from:http://www.cnblogs.com/weidagang2046/archive/2009/12/10/1620587.html   依赖注入(DI)是控制反转(IoC)的一种方式.目前,在.NET和Java领域已经有相当多基于DI思想的对象容器,如:Spring,Unity等.本文试图避免重复性地介绍DI基础知识和DI容器的使用,而是希望深一层探讨DI的本质和对象间关系,以达到合理设计避免滥用DI的目的.   依赖注入 vs 创建对象 有不少地方这样描述:"依赖注入改变了使用

DDD领域驱动设计基本理论知识总结

领域驱动设计之领域模型 加一个导航,关于如何设计聚合的详细思考,见这篇文章. 2004年Eric Evans 发表Domain-Driven Design –Tackling Complexity in the Heart of Software (领域驱动设计),简称Evans DDD.领域驱动设计分为两个阶段: 以一种领域专家.设计人员.开发人员都能理解的通用语言作为相互交流的工具,在交流的过程中发现领域概念,然后将这些概念设计成一个领域模型: 由领域模型驱动软件设计,用代码来实现该领域模型

领域驱动设计-相关理论

最近 Rafy 开源中心 启动刚一个月,在初始的讨论会上,成员们对面向对象设计.领域驱动设计等概念展开了大量的讨论. 下面我转载一篇文章,这篇文章的详细内容我都还没看完.不过,文章的结构正是我想要的!其结构非常清晰,很好地说明了领域驱动设计相关的起源.重点.模式.经典架构,以及一些后人扩展的新概念. 转载自<DDD领域驱动设计基本理论知识总结>,并稍微调整了一下内容顺序. 为什么面向对象比面向过程更能适应业务变化 对象将需求用类一个个隔开,就像用储物箱把东西一个个封装起来一样,需求变了,分几种

JavaScript闭包实例详解_javascript技巧

一.充电 1.一切(引用类型)都是对象,对象是属性的集合. 2.函数是一种对象,但是函数却不像数组一样--你可以说数组是对象的一种,因为数组就像是对象的一个子集一样.但是函数与对象之间,却不仅仅是一种包含和被包含的关系,函数和对象之间的关系比较复杂,甚至有一点鸡生蛋蛋生鸡的逻辑. function Fn() {this.name = '王福朋';this.year = 1988;} var fn1 = new Fn(); var obj = { a: 10, b: 20 };等价于var obj

C++ stringstream介绍,使用方法与例子

From: http://www.usidcbbs.com/read-htm-tid-1898.html   C++引入了ostringstream.istringstream.stringstream这三个类,要使用他们创建对象就必须包含sstream.h头文件. istringstream类用于执行C++风格的串流的输入操作. ostringstream类用于执行C风格的串流的输出操作. strstream类同时可以支持C风格的串流的输入输出操作. istringstream类是从istre

Pimpl常用法

对于规模较大的C++项目,头文件的互包含和互依赖关系经常困扰开发者.例如: class foo { public: foo(); void method_foo_b(const foo_a& b); private: void method_foo_c(const foo_b& c); private: foo_b b_; foo_c c_; }; int main(...) { foo fooi; } 如果要使得main或者一个必须包含foo的class通过编译,则不仅需要包含foo头文

面向设计原则理解

    面向对象设计(OOD)核心原则让我的程序模块达到"高内聚低耦合",这是来自于30年前兴起的结构化设计(structured Design),但是同样适用于我们的OOD. 1.高内聚:     高内聚是指某个特定模块(程序,类型)都应完成一系列相关功能,描述了不同程序,类型中方法,方法中不同操作描述的逻辑之间的距离相近.高内聚意味可维护性,可重新性,因为模块对外部的依赖少(功能的完备性).如果两个模块之间的修改,互不影响这说明模块之间是高内聚的.模块的内聚和其担当的职责成反比,即

用封装类来合理的设计PHP项目--谈PHP项目中类的封装

封装|设计|项目 编码对于合格的PHP程序员来说并不是什么难事(也许只是花费时间长短的问题),因此系统分析和设计这一阶段就显得尤为重要.不过本文并不打算讨论和需求分析.获取商业逻辑相关的话题,而是针对系统设计方面进行探讨.面临难题编码对于合格的PHP程序员来说并不是什么难事(也许只是花费时间长短的问题),因此系统分析和设计这一阶段就显得尤为重要.对于一个担任PHP项目的系统分析员来说,面临着两个难题: PHP语言本身的限制.这一点在复杂系统的面向对象设计中尤其显著.PHP的面向对象特性在现有版本

编程之禅 浅谈封装

作为一个整天与代码打交道的人,你真的会coding吗? 今天依旧来反思一下自身. 伊始 大一的时候,刚接触到了C语言,一门神奇的语言.老师就教导我们要多敲例子,照着书本敲就可以了.可能当时并没有真正的理解老师的意思,所以就只是照着课本敲,(尴尬的是,我真的就只是照着课本上一字一字的敲,-_-!!!)也因此养成了一种换习惯.那就是在接触到一个新语言的时候,总是情不自禁的缺乏思考的描摹.所以脱离了课本的我并不能完成什么比较独立的项目. 学而不思则罔,死而不学则殆! 当我认识到这一点的时候,已经过去很