艾伦霍勒布写道:“你不应该使用获取/设置function”,他是正确的?
艾伦霍勒布写了以下内容,
没有一些耦合,你不能有一个程序。 尽pipe如此,通过严格遵循OO(面向对象的)规则(最重要的是对象的实现应该完全从使用它的对象中隐藏),可以大大减less耦合。 例如,对象的实例variables(不是常量的成员字段)应始终保密。 期。 没有例外。 永远。 我是认真的。 (您可以偶尔使用受保护的方法,但受保护的实例variables是可憎的。)
这听起来合理,但他接着说,
你不应该使用get / set函数出于同样的原因 – 他们只是过于复杂的方式来公开一个字段(尽pipe访问函数返回成熟的对象而不是基本types的值是合理的,在返回的对象类是devise中的关键抽象)。
坦率地说,对我来说听起来很疯狂。
我理解隐藏信息的原理,但是如果没有访问器和修改器,就根本无法使用Java Bean。 我不知道如何在模型中没有访问器的情况下遵循MVCdevise,因为模型不能负责渲染视图。
但是,我是一个年轻的程序员,每天都会学习更多关于面向对象的devise。 也许有更多经验的人可以考虑这个问题。
艾伦霍勒布的文章供参考
- 为什么延伸是邪恶的
- 为什么Getter和Setter方法是邪恶的
相关问题:
- 爪哇:吸气剂和固化剂是邪恶的吗?
- 是不是真的没有使用setter和getters?
- 获得和设置functionstream行与C ++程序员?
- 你应该使用类中的访问器属性,还是仅仅从类之外?
我和Holub没有任何问题,告诉你通常应该避免改变一个对象的状态 ,而是用综合的方法(执行行为)来达到这个目的。 正如Corletk所指出的那样,在抽象的最高级别上长久而艰苦地思考是有智慧的,而不仅仅是对getter / setter进行粗心的编程,而只是让你在封装上做最后的运行。
然而,对于任何告诉你“永远不要”使用setter或者“永远”不能访问原始types的人来说,我都有很大的麻烦。 事实上,在所有情况下保持这种纯度所需的努力,最终会导致代码中的复杂性高于使用适当实施的属性。 你只需要有足够的理解知道你何时以短期的收益为代价来规避长期的痛苦。
霍勒布不相信你知道这个区别。 我认为知道差异是什么让你成为一个专业。
我认为艾伦·霍勒布(Allen Holub)在这篇文章中试图说的是以下内容。
getters和setter对于你想要封装的variables是有用的,但是你不必为所有的variables使用它们。 事实上,使用它们的所有variables是讨厌的代码气味。
程序员所遇到的麻烦,艾伦·霍勒布(Allen Holub)正确地指出,他们有时使用getter / setter来表示所有的variables。 而封装的目的就是失去了。
仔细阅读那篇文章。 霍勒布(Holub)提出,吸气人员和安装人员是一种邪恶的“默认反模式”,这是我们在devise系统时遇到的一个坏习惯; 因为我们可以。
思想过程应该是沿着路线的; 这个对象是做什么的? 它的职责是什么? 它的行为是什么? 它知道什么? 对这些问题进行长时间的思考,自然会导致您devise出可能暴露最高级别界面的类。
一辆车就是一个很好的例子。 它揭示了一个明确的,标准化的高层接口。 我不关心setSpeed(60)
…是MPH还是km / h? 我只是加速,巡航,减速。 我不必考虑setSteeringWheelAngle(getSteeringWheelAngle()+Math.rad(-1.5))
的细节,我只需turn(-1.5)
,细节将在setSteeringWheelAngle(getSteeringWheelAngle()+Math.rad(-1.5))
。
归结起来,“你可以而且应该弄清楚每个class级将被用于什么,它做了什么,它代表什么,并且暴露出最高水平的接口,以满足这些要求。吸气和吸气设备通常是一个警察,当程序员只是懒惰地做分析,确切地确定每个类是什么,什么不是,所以我们沿着“它什么都可以做”的方式走,吸气者和制定者是邪恶的!
有时一个class级的实际需求是不可预知的。 这很酷,现在只是指挥和使用getter / setter反模式,但是当你知道,通过经验,什么类正在使用,你可能会想要回滚和清理脏的低级界面。 基于“你希望你知道的东西,当你写第一个吸盘”的重构是相同的课程。 你不需要知道所有的事情就可以开始,只是你知道的越多,在这个过程中可能需要的返工就越less。
这是他正在推动的心态。 吸气剂和吸附剂是容易陷入的陷阱。
是的,豆基本上需要getter和setter,但对我来说bean是一个特例。 豆代表名词,事物,有形的可识别(如果不是物理的)物体。 不是很多对象实际上有自动行为; 大多数情况下,外部力量(包括人类)操纵事物,使其成为有生产力的东西。
daisy.setColor(Color.PINK)
非常有意义。 你还能做什么? 也许是一个火神的想法,使花想成为粉红色? 嗯?
吸气者和制定者有他们的邪恶? 地点。 就像所有非常好的OO事情一样,我们倾向于过度使用它们,因为它们是安全和熟悉的,更不用说简单了,所以如果新手没有看到或听到它们,可能会更好,至less在他们“ d掌握了心灵的东西。
(注意我来自.NET的“财产”angular度)
那么,简单地说 – 我不同意他。 他对于返回types的属性是一件坏事大惊小怪,因为它可能会破坏你的调用代码 – 但是方法参数也适用相同的参数。 如果你不能使用方法吗?
好的,方法参数可以被改变为扩大转换,但是……为什么…另外,请注意,在C#中var
关键字可以减轻很多这种痛苦。
访问者不是一个实现细节; 他们是公共API /合同。 是的,如果你打破了这个问题,你就有麻烦了。 这是什么时候变成了一个惊喜? 同样,访问者并不是不平凡的 – 也就是说,他们不仅仅是包装字段, 他们执行计算,逻辑检查,通知等,他们允许基于接口的状态抽象。 哦,多态 – 等等
在C#中,访问者的冗长特性(p3?4?) – public int Foo {get; private set;}
public int Foo {get; private set;}
– 完成工作。
最终,所有的代码都是向编译器expression我们意图的手段。 属性让我以types安全的,基于合同的,可validation的,可扩展的,多态的方式做到这一点 – 谢谢。 为什么我需要“修复”这个?
我在Allen Holub上做了一些额外的Googlesearch,看起来他在Java社区有他的对手的份额。
- 艾伦霍勒布是邪恶的
- 邪恶的裁判员
- 霍勒布又来了
最后一个特别指出。 评论员的文本是斜体的。
尽pipegetIdentity以“get”开始,但它不是一个访问器,因为它不仅仅返回一个字段。 它返回一个具有合理行为的复杂对象
哦,但是等等…那么只要你返回对象而不是原始types就可以使用访问器了吗? 现在,这是一个不同的故事,但对我来说却是愚蠢的。 有时你需要一个对象,有时你需要一个原始types。
另外,我注意到艾伦自从他上一篇专栏以来,已经从根本上缓和了自己的立场,即“永不使用存取器”的口号并没有遭遇一个例外。 也许他在几年之后意识到访问者确实达到了一个目的…
请记住,我没有将任何UI代码实际放入业务逻辑中。 我已经根据AWT(抽象窗口工具包)或Swing(都是抽象层)编写了UI层。
好的。 如果你在SWT上编写你的应用程序呢? 在这种情况下,“抽象”真的是AWT吗? 正视它:这个build议只是导致你在你的业务逻辑中编写UI代码。 多么伟大的原则。 毕竟,只有至less十年之后,我们才将这种做法确定为可以在项目中做出的最糟糕的devise决策之一。
我的问题是作为一个新手程序员有时在网上磕磕绊绊的文章,给他们更多的信任,那么我应该。 也许这是其中的一种情况。
吸气剂和吸附剂只是用来掩饰私人variables。
重复霍勒布已经说过的话是没有意义的,但问题的关键在于,阶级应该代表行为而不仅仅是状态。
当这样的想法呈现给我时,我喜欢看看我使用的库和框架,以及我喜欢使用的框架。
例如,虽然有些人会不同意,但我喜欢Java Standard API。 我也喜欢Spring框架。 看看这些库中的类,你会注意到很less有那些只是暴露一些内部variables的setter和getter。 有一些名为 getX的方法,但这并不意味着它是传统意义上的吸气剂。
所以,我认为他有一个观点,就是这样的:每次你在Eclipse(或者你select的IDE)中select“Generate getters / setters”时,你应该退后一步,想知道你在做什么。 公开这个内部表示是否真的是合适的,还是我在某个步骤搞乱了我的devise?
我不相信他说永远不会使用get / set,而是使用get / set字段并不比只是公开字段(例如公共string名称与公共string名称{get; set;})更好。
如果使用get / set,则会限制OO的信息隐藏,这可能会将您locking在不良的界面中。
在上面的例子中,Name是一个string, 如果以后要更改devise以添加多个名称,该怎么办? 该接口只显示一个单一的string,所以我们不能添加更多而不破坏现有的实现。
但是,如果不是使用get / set,而是最初有一个方法,例如Add(string名称),则可以在内部单独处理名称,或者添加到列表中,或者在外部调用Add方法的次数为想要添加的次数更多的名字。
面向对象的目标是devise一个抽象层次; 不要暴露比你绝对必须的更多的细节。
如果你用一个get / set包装了一个原始types,那么你有可能打破了这个原则。
当然,如果你相信面向对象的目标, 我发现大多数不是,不是真的,他们只是使用对象作为一个方便的方式来组合function代码。
当类只不过是一个没有真正的一致性的数据包,或者当它真的是基本的(如点类)时,公共variables是有意义的。 一般来说,如果一个class级中有变数,你认为可能不应该是公开的,那就意味着这个class级有一定的连贯性,variables之间应该有一定的关系,所以所有variables都应该是私人的。
当他们反映某种连贯的想法的时候,吸气剂和吸附剂是有意义的。 例如,在多边形类中,给定顶点的x和y坐标在类边界之外具有含义。 让getter成为可能是有意义的,而且有setter可能是有意义的。 在银行账户类中,余额可能被存储为私有variables,几乎肯定应该有一个getter。 如果它具有setter,则需要内置日志logging以保持可审计性。
getter和setter比公共variables有一些优点。 它们提供了一些接口和实现的分离。 仅仅因为一个点有一个.getX()
函数并不意味着必须有一个x,因为.getX()
和.setX()
可以使用径向坐标很好地工作。 另一个是可以维护类不variables,通过做任何必要的事情来保持类中的一致性。 另一个就是可以在一个集合上触发function,比如logging银行账户余额。
然而,对于更抽象的类,成员variables会失去个人意义,只有在上下文中才有意义。 例如,您不需要知道C ++stream类的所有内部variables。 您需要知道如何获取元素,以及如何执行各种其他操作。 如果你指望确切的内部结构,你会陷入细节,可以在编译器或版本之间任意变化。
所以,我会说几乎完全使用私有variables,getters和setter在对象行为有真正的意义,而不是其他。
只是因为吸气人员和安装人员经常被滥用并不意味着他们是无用的。
getter / setter的麻烦在于他们试图伪装封装,但实际上却是通过暴露内部来破坏封装。 其次,他们正在试图做两件独立的事情 – 提供和控制他们的国家 – 结果做得不好。
它打破封装,因为当你调用一个get / set方法时,你首先需要知道你想要改变的字段的名字(或者有一个好主意),然后你必须知道它的types,例如。 你不能打电话
setPositionX("some string");
如果你知道字段的名称和types,而且setter是公开的,那么任何人都可以调用这个方法,就好像它是公共领域一样,这只是一个更复杂的方法,为什么不简化它,使它首先是一个公共领域。
通过允许访问它的状态,但试图同时控制它,一个get / set方法只是混淆了事物,结果是无用的锅炉或误导,没有实际做它所做的,用户可能不会期望的效果。 如果需要错误检查,可以这样调用
public void tryPositionX(int x) throws InvalidParameterException{ if (x >= 0) this.x = x; else throw new InvalidParameterException("Holy Negatives Batman!"); }
或者如果需要额外的代码,可以根据整个方法的作用将其称为更精确的名称。
tryPositionXAndLog(int x) throws InvalidParameterException{ tryPositionX(x); numChanges++; }
恕我直言,需要获得者/安装者做一些工作往往是一个糟糕的devise的症状。 利用“告诉,不要问”的原则,或者重新思考为什么一个对象需要首先发送它的状态数据。 公开改变对象的行为而不是状态的方法。 这样做的好处包括更简单的维护和更高的可扩展性。
你也提到MVC,并说一个模型不能为它的观点负责,在这种情况下, 艾伦·霍勒布(Allen Holub)举了一个抽象层的例子,它有一个“给我一个JComponent-表示你的标识类“他说这将”隔离身份从系统的其他部分表示的方式“。 我没有足够的经验来评论这是否有效,但从表面上看,这听起来是一个体面的想法。
如果公共获得者/设置者提供对实现细节的访问权限,则它们是不好的。 然而,提供对对象属性的访问并为此使用getter / setter是合理的。 例如,如果Car有颜色属性,让客户使用getter来“观察”它是可以接受的。 如果某些客户需要重新着色汽车的能力,那么这个class级可以提供一个二传手(虽然“recolor”更清晰)。 不要让客户知道属性如何存储在对象中,它们是如何维护的,等等。
嗯…他从来没有听说过封装的概念。 Getter和Setter方法被用来控制对“成员”的访问。 通过使所有的领域公开可见…任何人都可以写任何他们想要的价值,从而完全无效的整个对象。
以防有人对封装概念有些模糊,请在这里阅读:
封装(计算机科学)
…如果它们真的很邪恶,.NET是否会将Property概念构build成语言? (Getter和Setter方法看起来更漂亮一些)
编辑
文章确实提到封装:
“ Getters和setter对于你想要封装的variables是有用的,但是你不必为所有的variables使用它们,事实上,对所有variables使用它们都是令人讨厌的代码味道。
从长远来看,使用这种方法会导致维护代码变得非常困难。 如果您发现跨越数年的项目中途需要封装一个字段,则必须在软件的每个地方更新该字段的每一个参考来获得收益。 听起来更聪明一些,先使用适当的封装,然后安全的头痛。
我认为getter和setter只能用于需要访问或更改类的variables。 这就是说,我不相信variables应该是公开的,除非它们是静态的。 这是因为使公共variables不是静态的可以导致它们被不希望地改变。 假设你有一个不小心使用公共variables的开发人员。 然后,他从另一个类访问一个variables,并且没有意义地改变它。 现在,他的软件出现了这样的错误。 这就是为什么我相信正确使用getter和setter,但是你并不需要每个私有或受保护的variables。