JavaRush /Java 博客 /Random-ZH /获取器/设置器。邪恶的。和时期
angelina
第 5 级

获取器/设置器。邪恶的。和时期

已在 Random-ZH 群组中发布
文章作者:Egor Bugaenko 2014 年 9 月 19 日 | 发表于:Core Java 获取器/设置器。 邪恶的。 和点 - 1这个古老的争论是由 Allen Holub 在他的著名文章中发起的,早在 2003 年,为什么 getter 和 setter 方法是邪恶的- getter/setter 是反模式吗?我们应该避免它们,还是我们应该这样做?面向对象编程中必然需要。我将在这次讨论中添加我的两分钱。下面文本的要点是:getter 和 setter 是不好的做法;使用它们的人没有任何借口。但再次强调,为了避免误解,我并不是建议尽可能避免使用 get/set。不。我是说你甚至没有让他们接近你的代码获取器/设置器。 邪恶的。 和点 - 2您对此声明有何看法?值得你关注吗?您使用 get/set 模式已经有 15 年了,您是一位受人尊敬的 Java 架构师吗?而且你连一个陌生人的胡言乱语都不想听吗?嗯...我理解你的感受。我也有同样的感觉,直到我读到 David West 的书《对象思维》——这是我读过的关于面向对象编程的最好的书。所以,请。冷静下来,尝试理解我想要解释的内容。 争议主题 在面向对象的世界中,存在一些反对“访问器”(getter 和 setter 的另一个名称)的争论。它们都是非常正确的论点。让我们快速浏览一下它们。 询问,不要告诉:艾伦·霍鲁布(Allen Holub)说,“不要询问完成工作所需的信息;‘询问’拥有该信息的实体来为您完成工作。” 违反封装原则:一个对象可以被其他对象拆开,因为它们可以通过 setter 将任何数据嵌入到该对象中。对象根本无法足够安全地封装自己的状态,因为任何人都可以更改该状态。 实现细节揭示:如果您可以从另一个对象获取一个对象,那么我们就过于依赖第一个对象的实现细节。如果明天它发生变化(例如,结果类型),那么我们将不得不更改代码。上述所有理由当然都有道理,但这忽略了最重要的一点。 基本误解 大多数程序员认为对象是具有方法的数据结构。我引用Bozhidar Bozhanov的文章:Getters和Setters并不邪恶。但大多数为其创建 getter 和 setter 的对象只包含数据。这个误会是一个巨大的误会造成的!对象“不仅仅存储数据”。对象不是附加方法的数据结构。“数据存储”的概念来自面向对象的编程和过程语言,尤其是 C 和 COBOL。我会再次重复:对象不仅仅是数据元素和操作它们的函数的集合。对象不是数据对象。然后怎样呢? 球和狗 在真正的面向对象编程中,对象是有生命的存在,就像你和我一样。它们是活的有机体,有自己的行为、属性和生命周期。一个活的有机体可以有一个二传手吗?你可以给狗附上(“设置”)一个球吗?别想了。但这正是下面这段代码的作用:
Dog dog = new Dog();
dog.setBall(new Ball());
那么你觉得怎么样?你能把球从狗身上拿下来吗?好吧,我们假设你可以。万一她吃了它而你给她做了手术。在这种情况下,是的,您将能够从狗那里得到(“得到”)球。这正是我要说的:
Dog dog = new Dog();
Ball ball = dog.getBall();
或者一个更荒谬的例子:
Dog dog = new Dog();
dog.setWeight("23kg");
你能想象现实生活中的情况吗?听起来你每天都在写吗?如果是,那么您就是一名过程程序员。承认吧。David West 在他的书第 30 页上是这样说的: 将成功的程序开发人员转变为成功的目标开发人员的第一步是脑白质切除术。您需要脑叶白质切除术吗?我确实需要它,并且是在阅读 West 的《对象思维》一书时得到的。 客观思考 开始像对象一样思考,您将立即重命名这些方法。您可能会得到以下结果:
Dog dog = new Dog();
dog.take(new Ball());
Ball ball = dog.give();
现在,我们把狗当作一种真正的动物,它可以从我们手中夺走球,如果我们要求的话,它也可以把它还给我们。为了以防万一,我注意到狗不能返回 NULL。狗就是不知道 NULL 是什么!客观思考(思考)立即从你的代码中删除NULL 引用获取器/设置器。 邪恶的。 还有点 - 3
一条叫旺达的鱼 (1988) 查尔斯·克莱顿 (Charles Crichton)
此外,客观思维将导致对象的不变性,例如我们示例中的“狗的重量”。您可以将代码重写为如下所示:
Dog dog = new Dog("23kg");
int weight = dog.weight();
狗是一种不可改变的生物体,不允许外界任何人改变它的重量、大小、名称等。她可以根据要求“说出”她的体重或姓名。公开对对象的某些“内部”属性的查询的公共方法没有任何问题。但这些方法不是“getters”,它们永远不应该接收“get”前缀。我们无法“摆脱”狗。我们不知道她的名字。我们请她告诉我们她的名字。你看得到差别吗?我们在这里甚至不讨论语义。我们将过程式编程方法与面向对象的编程方法区分开来。在过程编程中,我们处理数据、操作它、获取它、设置它,并在必要时删除它。我们是掌控者,数据只是被动的组成部分。狗对我们来说毫无意义——它只是“包含数据”。她没有自己的生活。我们可以自由地从中获取(get)我们需要的一切,并将任何数据放入(设置)其中。这就是 C、COBOL、Pascal 和其他过程语言的工作原理(worked)。而在面向对象的世界中情况则完全相反。在这里,我们将物体视为活的有机体,有自己的出生日期和死亡时刻,有自己的个性和习惯,如果你愿意的话。我们可以要求狗给我们一个数据(例如它的重量),它可以将信息返回给我们。但永远记住,狗是活跃的组成部分。她决定请求后会发生什么。这就是为什么对象的方法以 set 或 get 开头是绝对错误的。这甚至不像许多人认为的那样违反封装性。这是因为您要么像对象一样思考,要么仍在使用 Java 语法编写 COBOL。 附言。是的,您可能会问:“JavaBeans、JPA、JAXB 和许多其他依赖于 get/set 的 Java API 怎么样?” Ruby 中可以更轻松地创建访问器的内置函数怎么样?好吧,我能告诉你什么呢...你运气不好。留在程序 COBOL 的原始世界中比理解和拥抱真实对象的奇妙世界要容易得多。 附注_ 我忘了说,是的,通过 setter 插入依赖项也是一种可怕的反模式。但下一篇文章将详细介绍这一点! 来源文章
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION