我并不想开始一个“邪恶的”系列文章,但是一些读者要我解释为什么上个月的专栏中提及要避免使用 get/set方法,“为什么extends是邪恶的?” 虽然getter/setter方法在java里处处可见,但它们不是完全OO的,实际上,它们会破坏你代码的可维护性,而且,当你的程序并不需要一个从OO方面来讲很好的的设计时。大量存在的getter 和setter方法是一个危险的信号。
这篇文章解释为什么你不应当使用getters 和 setters,什么情况下使用,并且给出一个帮助你打破getter/setter思维定势的设计方法。
上个月的专栏里,我很惊讶一些读者的评论,“为什么extends是邪恶的”,一些人认为我在说OO实在是过于简单因为extends存在很多问题,好像把二个概念等同起来了。这明显不是我的所想所言,所以我在这里澄清一些本来的观点。
这篇专栏和上月的文章是关于设计的,设计,很自然要抛弃一系列旧有的东西。每一个选择都有好的一面和坏的一面,你应根据需要做一个全面客观的权衡,好和坏都是相对的,毕竟,一个好的选择,从另一个角度来讲可能很不利。
如果你不明白一个论点的二面性,就不能做出明智的选择,实际上,如果你看不到行为的副作用,根本就不能做设计,只能在黑暗中前行。这个观点并不意外,在四人帮的的设计模式每一章中,都包含了一段“Consequences”来描述什么时候、为什么使用该模式,和什么情况下不适宜。
一些语言的特性或习惯编程用法存在问题,并不是说你就应在任何情况下都不用要用它们。或者,仅仅因为一些用法已经很常见,你就应该去用它们。不知情的程序员用会Sun或MS提供的东西写很多的程序,这不会提高他们的编程或设计能力。Java包里有大量的代码,但是我相信,还是有一部份,让他们的作者感到窘迫而想重新写的。
另外,市场或政策经常推动设计习惯。有时候,程序员会做出糟糕的决定,但是公司想要强调自己能达到的技术,所以不再说你做的这些不够理想,他们为这个糟糕的解决方案全力而为,因此,当你的程序实现都是因为“被期望这样做”,你是不负责的。很多失败的EJB项目验证了一点,基于EJB的技术被正确使用的时候非常棒。但是它经常用的不合适宜而造成一些公司的困境。
OO系统的一个基本原则是一个Object不应暴露它的实现细节,这样,当你改变了实现细节,就可以不用改变使用了该对像的的代码部份。所以,你应当避免getter 和 setter 函数,因为它们主要用来访问实现细节。
来看看为什么,假设你的程序中有1000处调用 getX() 方法,假设每个调用都返回一个特定类型,你可能把 getX() 的返回值存在一个局部变量中,那个变量类型必须匹配返回值类型,如果你需要改变对像的实现细节而改变了X的类型,你将陷入巨大的麻烦中。
如果X是 int 类型,但是现在必须变为long ,将得到1000个编译错误,如果你通过把返回值改为int而修正这个错误,代码编译正确,但是结果不正确(返回值被缩短了)。你必须在1000个调用处逐个修改。我确定你不愿做这样的工作。
OO系统的一个基础原则是数据提取。你可能会完全隐藏对像从静态程序实现消息句柄的方法,这也就是为什么所有的实例变量(一个类的非静态fields)应当是private的一个原因。
如果你让一个实例变量是public 的,那么你以后不能再改变fields ,因为这可能会破坏外面代码对它的使用。你不想仅仅因为改变了这个类,而搜索1000处对它的调用吧。
隐藏实现原则导致了对OO系统质量的一个严峻考验,你可以对一个类的定义做大的改变—甚至是抛弃所有已做好的,并且替换成一个完全不同的实现吗,而且不能影响任何调用了该类的对像。这种模块化使面向对像变得更容易维护,如果没有实现隐藏,其它的OO特性也没有什么可使用点了 。
Getter 和 Setter 方法(或者叫accessors)是危险的,同样原因,public fields 也是危险的:它们提供外部访问实现细节的方法。如果你需要改变被访问field的类型呢?你同样不得不改变accessors的返回值。你这个返回值已经被用在很多地方了,所以你必须改变所有相关代码。我想限制改变一个单个类的定义所带来的影响,不想它们影响到整个程序。
由于accessors 违反了封闭原则,你可以说如果一个系统大量的,不适宜地使了accessors就不是面向对像的。如果你参加了设计过程,并且反对那样编码,你可以发现在你的程序里几乎没有accessors. 这个过程很重要,我想在本篇快要结束的时候,对这个问题多说二句。
Getter/setter 方法的缺点并不意味着一些数据不能在系统中传递。但是,应尽可能地减少数据移动。我的经验是系统的可维护性和数据在object 之间的流动数量成反比。你可以消除所有的数据移动。
通过仔细的设计和集中精力于你所必须做的事,你可以消除你程序中大部份的getter/setter 方法。不要要求你工作需要的信息,去找含有你需要信息的object,所有的accessors 都可以找到存在理由,因为设计者不去思考关于模型:他们发送消息和runtime object ,从一个对像到另一个对像。他们错误地设计一个类,并且试着把这些类生硬地塞进动态模型。这个方法是不对的。为建立一个静态模型,你需要找到类之间的关系,并且这些关系与message flow 之间应正确相符。当一个类的对像发送消息到另一个类的对像时,这二个类之间存在一种关系。静态模型的主要目的是为动态模型捕捉这种关系信息。
如果对动态模型没有一个清晰的定义,仅是猜测怎样使用一个类的对像的话,accessor方法会经常出现在你的模型中,由于不能预知是否需要它,所以必须提供尽可能多的访问。这种猜测设计的策略是多数是很低效的,你浪费时间于写无用的方法(或给类增加不必要的功能)
当过程程序员也采纳java时,他们倾向于以熟悉的方法编码,过程化语言没有类,但是他们有C的结构体(你可以想:没有方法的类)。它看起来很正常,可以通过建造一个没有方法,除了public fields 什么都没有的类来模拟一个结构体,这些过程化的程序员读到此处时可能会认为filed应该是private,于是,他们把fields 私有化并且让它支持public 的accessor方法。然后进行了复杂的public access,这样子确实不能让系统OO起来。
英文:http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html?page=2
分享到:
相关推荐
提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class,java * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class,java * 反射工具类. 提供调用getter/...
提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实...
当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的...
java 的eclipse或idea等 定义变量时 直接引入lombok.jar包 在类外部 引入@AllArgsConstructor @NoArgsConstructor @Data 简便方法引入getter/setter/tostring等方法
VS2005(C#)插件Getter/Setter生成器是一款专为Visual Studio 2005设计的扩展工具,旨在提高C#编程的效率。该插件的主要功能是自动生成属性的getter和setter方法,这在编写面向对象的代码时非常常见。通过自动化这个...
在编写Java类时,当需要为某个属性添加getter或setter方法,只需将光标放在属性声明上,然后使用快捷键(通常为Alt+Insert)或者右键选择“Generate” -> “Getter/Setter”。插件会根据当前类的编码规范自动生成...
3. getter/setter 方法的缺陷:传统的 getter/setter 方法实现方式存在一些缺陷,例如需要为每个字段编写大量的代码,且无法方便地定义字段的类型限制。 4. 使用魔术方法来实现 getter/setter:PHP5 中可以使用魔术...
这个简单的脚本向Dreamweaver添加了一条命令,以自动为类中的属性生成getter / setter(就像其他IDE(例如eclipse和netbeans一样)。 对于使用ORM(例如主义)PHP开发人员来说,它非常舒适。 (要安装,请将.htm和....
在iOS开发中,getter和setter方法是Objective-C和Swift中对象属性访问的重要组成部分。它们用于获取(get)和设置(set)对象的属性值。本文将深入探讨getter和setter的概念、作用以及如何在代码中使用它们。 首先...
2. **启用getter/setter支持**: 在Jackson中,如果一个字段没有getter或setter方法,那么默认情况下它不会被序列化到JSON中。因此,只包含getter和setter的方法的属性会被考虑进行转换。 3. **配置Jackson库**: ...
在Java编程中,getter和setter方法是用于封装对象属性的重要工具。Eclipse作为一个强大的集成开发环境(IDE),提供了丰富的代码生成功能,包括自动为getter和setter添加注释。本篇文章将详细探讨如何在Eclipse中...
如何使用它使用 getter/setter 方法创建对象 // Create an object with getter/setter methodvar obj = { name : new getterSetter ( 'John' )} ;// Access the property in read or write modeconsole . log ( obj ...
它们遵循特定的命名规则,例如,对于一个名为`name`的字段,其getter方法通常是`getName()`,setter方法是`setName(String name)`。 在Eclipse中,当我们为字段添加注释后,可以通过以下步骤将这些注释同步到getter...
在Java编程中,getter和setter方法是面向对象设计的一个重要组成部分。它们用于封装类的私有成员变量,提供对外访问和修改这些变量的途径。Eclipse作为一款强大的Java集成开发环境(IDE),提供了自动化生成getter和...
getter和setter方法是面向对象编程中的常见设计模式,它们分别用于获取和设置对象的私有属性值。通过提供这些方法,开发者可以控制对对象内部状态的访问,同时保持数据的安全性。注释的getter和setter方法通常包括了...
在编程领域,尤其是在Java开发中,getter和setter方法是面向对象设计的重要组成部分,它们用于封装对象的属性,确保数据的安全性。然而,手动编写这些方法可能会耗费大量时间。为了解决这个问题,开发者们通常会利用...
然而,在实际开发过程中,有时我们需要自动生成带有注释的getter和setter方法,以提高代码的可读性和规范性。IDEA默认生成的getter和setter方法可能不包含注释,这可能给团队协作带来不便。本文将详细解释如何配置...
在Java编程中,getter和setter方法是面向对象设计原则中的封装特性的重要体现。它们用于访问和修改类的私有成员变量,确保数据的安全性。Eclipse是一款广泛使用的集成开发环境(IDE),它提供了丰富的代码自动补全和...
在Eclipse这款强大的Java开发工具中,为类的属性生成setter和getter方法是常见的操作,这些方法用于封装类的私有变量,确保数据的安全性。然而,为了代码的可读性和维护性,开发者通常会在setter和getter方法上添加...