这个问题在这里已经有答案了:

艾伦·霍鲁布 (Allen Holub) 写道:

如果没有一些耦合,你就不可能拥有一个程序。尽管如此,您可以通过盲目地遵循 OO(面向对象)规则来大大减少耦合(最重要的是对象的实现应该对使用它的对象完全隐藏)。例如,对象的实例变量(不是常量的成员字段)应该始终是私有的。时期。没有例外。曾经。我是认真的。(您偶尔可以有效地使用受保护的方法,但受保护的实例变量是令人厌恶的。)

这听起来很有道理,但他接着说,

你应该 切勿使用 get/set 函数 出于同样的原因,它们只是将字段公开的过于复杂的方法(尽管在返回对象的类是设计中的关键抽象的情况下,返回完整对象而不是基本类型值的访问函数是合理的) )。

坦率地说,这对我来说听起来很疯狂。

我了解信息隐藏的原理,但是如果没有访问器和修改器,您根本无法使用 Java bean。我不知道模型中没有访问器的情况下如何遵循 MVC 设计,因为模型 不能 负责渲染视图。

然而,我是一个年轻的程序员,每天我都会学到更多关于面向对象设计的知识。也许有更多经验的人可以权衡这个问题。

Allen Holub 的文章供参考


相关问题:

有帮助吗?

解决方案

我在Holub告诉您通常应该避免更改该问题时没有问题 状态 对象的目的,而是诉诸于集成方法(行为执行)以实现这一目的。正如Corletk指出的那样,长时间思考最高水平的抽象是有智慧的,而不仅仅是与Getters/setter无意识地编程,而Getters/setter只需让您绕过封装。

但是,我与任何告诉您您“永远不要”使用Setter或不应该“永远”访问原始类型的人遇到了很多麻烦。确实,维持这种纯度所需的努力 全部 与使用适当实现的属性相比,案例可能并且最终会导致代码中的复杂性更多。您只需要有足够的意识就可以知道何时以牺牲长期痛苦为代价的短期收益规则。

Holub不相信您知道区别。我认为知道差异是使您成为专业人士的原因。

其他提示

仔细阅读该文章。霍鲁布(Holub)提出了一个邪恶的“默认对抗者”的观点,这是我们在设计系统时陷入的坏习惯。因为我们可以。

思考过程应沿线;这个对象是什么 ?它的责任是什么?它的行为是什么?它知道什么?长时间思考这些问题,您自然会导致您设计的课程,以揭示可能的最高水平界面。

汽车就是一个很好的例子。它暴露了一个定义明确的高级界面。我不关心自己 setSpeed(60)...是mph还是km/h?我只是加速,巡航,减速。我不必考虑细节 setSteeringWheelAngle(getSteeringWheelAngle()+Math.rad(-1.5)), , 我只是 turn(-1.5), ,细节得到照顾 在引擎盖下.

它归结为“您可以并且应该弄清楚每个班级的用途,做什么,代表什么,并揭露满足这些要求的最高级别接口。程序员只是懒惰地进行确定每个班级的分析,而不是,因此我们走上了“它可以做任何事情”的道路。被杀死者和二传手是邪恶的!

有时,班级的实际要求提前不可知。这很酷,现在只需使用getter/setter antpattern,但是当您知道,通过经验,课程的用途,您可能想卷土重来并清理肮脏的低级界面。基于“首先写傻瓜何时写傻瓜时知道的东西”的重构是该课程的标准。您不必知道一切就可以开始,这只是您所知道的越多,在途中需要的返工就越少。

那就是他正在促进的心态。获取器和固定器是一个容易陷入的陷阱。

是的,豆子基本上需要Getters和Setter,但是对我来说,豆是一种特殊情况。豆表示名词,事物,有形可识别(如果不是物理)对象。实际上,没有很多对象具有自动行为;大多数时候,包括人类在内的外部力量操纵了事情,以使它们产生生产力。

daisy.setColor(Color.PINK) 完全有道理。你还能做什么?也许是瓦肯人的思维融合,使花 是粉红色?嗯?

有人和二传手有他们的邪恶?地方。就像所有非常好的东西一样,我们倾向于过度使用它们,因为它们是安全和熟悉的,更不用说简单了,因此,如果菜鸟看不到或听到它们,至少在它们'''' D掌握了思维融合的东西。

我认为艾伦·霍鲁布(Allen Holub)试图说的是 这个 文章,如下。

Getters和Setters对于您特定要封装的变量可能很有用,但是您不必将它们用于所有变量。实际上,将它们用于所有变量都是令人讨厌的代码气味。

编程人员的麻烦,艾伦·霍鲁布(Allen Holub)指出的是,他们有时会为所有变量使用getters/setters。并且封装的目的丢失了。

(请注意,我是从.NET“属性”角度来的)

好吧,简单地 - 我不同意他的看法;他对属性的返回类型是一件坏事大惊小怪,因为它可能会破坏您的呼叫代码 - 但是 确切地 相同的参数将适用于方法参数。如果您也不能使用方法?

好的,方法参数可以作为扩大转换而更改,但是....为什么...另外,请注意,在C#中, var 关键字可以减轻这种感知的疼痛。

登录器是 不是 实施细节;他们是公共API /合同。是的,如果您打破碰撞,您会遇到麻烦。什么时候感到惊讶?同样,访问者的非平凡并不少见 - 即他们所做的不仅仅是 只是 包装字段;他们执行计算,逻辑检查,通知等,并且允许基于界面的状态抽象。哦,多态性 - 等等

RE登录的详细性质(P3?4?) - 在C#中: public int Foo {get; private set;} - 任务完成。

最终,所有代码都是向编译器表达我们意图的一种手段。属性让我以一种类型的,基于合同的,可验证的,可扩展的,多态性的方式来做这件事 - 谢谢。为什么我需要“修复”此问题?

getters和setter只能用掩模即可公开私人变量。

重复Holub所说的毫无意义,但其关键是班级应该代表行为,而不仅仅是声明。

我在艾伦·霍鲁布(Allen Holub)上进行了一些谷歌搜索,似乎他在爪哇社区中有很多对手。

最后一个是特别指的。评论员的文字含义斜体。

尽管Getidentity以“ GET”开头,但它不是访问者,因为它不仅仅是返回字段。它返回具有合理行为的复杂对象

哦,但是等等...然后,只要您返回对象而不是原始类型,就可以使用访问器?现在这是一个不同的故事,但这对我来说就像愚蠢。有时您需要一个对象,有时您需要一种原始类型。

另外,我注意到艾伦(Allen)自从他上一列在同一主题上的专栏上就从根本上削弱了自己的位置,在那个主题上,咒语“从不使用访问者”没有遭受一个例外。也许他在几年后意识到,饰品毕竟确实有目的。

请记住,我实际上没有将任何UI代码放入业务逻辑中。我已经用AWT(抽象窗口工具包)或秋千编写了UI层,它们都是抽象层。

好一个。如果您在SWT上编写应用程序怎么办?在这种情况下,“抽象”真的很敬畏?面对现实:此建议只会导致您在业务逻辑中编写UI代码。多么伟大的原则。毕竟,自从我们将这种做法确定为您可以在项目中做出的最糟糕的设计决策之一以来,至少只有十年。

我的问题是,作为新手程序员有时会绊倒互联网上的文章,并给他们更多的信任。也许这是其中一种情况。

当向我提出这样的想法时,我喜欢看一下我使用的库和框架以及我喜欢使用的图书馆和框架。

例如,尽管有些会不同意,但我喜欢Java标准API。我也喜欢春季框架。查看这些库中的类,您会注意到很少有一些固定器和获取器只是为了暴露某些内部变量。有方法 命名 getx,但这并不意味着它是传统意义上的getter。

因此,我认为他有一个观点,就是这样:每次按Eclipse(或您选择的IDE)选择“生成Geters/Setters”时,您应该退后一步,想知道自己在做什么。公开这种内部表示真的很合适,还是我在某个步骤中弄乱了我的设计?

我不相信他是说永远不会使用get/set,而是要在字段中使用get/set,这比仅仅使该字段公开(例如公开字符串名称与公共字符串名称{get; set; set;})更好。

如果使用get/set,它会限制OO的信息隐藏,从而有可能将您锁定在不良界面中。

在上面的示例中,名称是字符串;如果我们以后要更改设计以添加多个名称怎么办?该接口仅曝光一个字符串,因此我们在不破坏现有实现的情况下无法添加更多。

但是,如果不使用get/set,您最初有一个方法,例如add(字符串名称),您可以在内部进行单独处理或添加到列表或不添加的方法,并在外部将添加方法称为多次,以添加添加更多名称。

OO目标是以一定程度的抽象设计。不要揭露比绝对需要的更多细节。

如果您刚刚用GET/SET包裹了原始类型,那么您打破了这个宗旨。

当然,这是您相信OO目标;我发现大多数人并不是真的,他们只是使用对象作为分组功能代码的一种说明方法。

当课程不过是没有真正连贯性的一堆数据时,或者当它确实是真正的,真正的基本(例如点类)时,公共变量是有道理的。通常,如果您认为可能不应该公开的类中有任何变量,则意味着该类具有一定的连贯性,并且变量具有应维护的一定关系,因此所有变量都应私有。

当捕获者反映某种连贯的想法时,他们就会变得有意义。例如,在多边形类中,给定顶点的x和y坐标具有在类边界之外的含义。有了获得球员可能是有意义的,拥有固定器可能是有意义的。在银行帐户类中,余额可能被存储为私人变量,几乎可以肯定应该有一个。如果有一个设置器,则需要内置日志记录以保持可审核性。

与公共变量相比,Getters和Setters有一些优势。它们提供了界面和实现的一定分离。只是因为一个要点有一个 .getX() 函数并不意味着必须有X,因为 .getX().setX() 可以使径向坐标正常工作。另一个是,可以通过执行任何必要的事情来使班级在二传手中保持一致,从而可以维护班级不变性。另一个是有可能具有触发设置的功能,例如银行帐户余额的日志记录。

但是,对于更抽象的类别,成员变量失去了个人意义,只有在上下文中才有意义。例如,您不需要知道C ++流类的所有内部变量。您需要知道如何使元素进出,以及如何执行其他各种动作。如果您依靠确切的内部结构,则会详细介绍可以在编译器或版本之间任意变化的详细信息。

因此,我会说几乎只使用私人变量,在对象行为中具有真正含义的私人变量,而不是其他。

仅仅因为待机和播放器经常被过度使用并不意味着它们没有用。

getter/setter 的问题在于他们试图伪造封装,但实际上他们通过暴露其内部结构来破坏它。其次,他们试图做两件不同的事情——提供对他们状态的访问和控制他们的状态——但最终都没有做得很好。

它破坏了封装,因为当您调用 get/set 方法时,您首先需要知道要更改的字段的名称(或有一个好主意),其次您必须知道它的类型,例如。你不能打电话

setPositionX("some string");

如果您知道字段的名称和类型,并且 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++;
}

恕我直言,需要 getter/setter 来使某些东西正常工作通常是糟糕设计的症状。利用“告诉,不要问”原则,或者重新思考为什么对象需要首先发送其状态数据。公开改变对象行为而不是状态的方法。这样做的好处包括更容易维护和提高可扩展性。

您也提到了 MVC,并说模型不能对其视图负责,对于这种情况 Allen Holub 给出了一个通过“给我一个代表你的身份类的 JComponent”来创建抽象层的示例 他说,这将“隔离系统的其余部分。”我的经验不足以评论是否有效,但从表面上看,这听起来是一个体面的想法。

如果公共Getters/Setter提供对实施详细信息的访问权限,则它们是不好的。但是,为此提供对对象属性的访问并使用getters/setter是合理的。例如,如果汽车具有颜色属性,则可以接受客户使用Getter“观察”它。如果某些客户需要重新着色汽车的能力,则类可以提供一个设置器(虽然“重塑”更为清晰)。重要的是不要让客户知道属性是如何存储在对象,如何维护中等等的。

嗯...他从未听说过封装的概念。 getter和setter方法已适当,以控制对类成员的访问。通过使所有字段公开可见...任何人都可以为其编写任何想要的价值观,从而使整个对象完全无效。

以防万一任何人对封装的概念有些模糊,请在此处阅读:

封装(计算机科学)

...如果它们真的很邪恶,.NET会将财产概念建立在语言中吗? (看起来更漂亮的Getter和Setter方法)

编辑

本文确实提到了封装:

"Getters和Setters对于您特定要封装的变量可能很有用,但是您不必将它们用于所有变量。实际上,将它们用于所有变量都是令人讨厌的代码气味。"

从长远来看,使用此方法将极难维护代码。如果您在一个跨越数年的项目中找到需要封装的项目的一半,则必须更新软件中各地的该字段的每个参考,以获取好处。听起来很聪明,可以在前面使用适当的封装,并在以后安全的头痛。

我认为,Getters和Setter只能用于将班级外访问或更改的变量使用。话虽如此,除非变量静态,否则我不认为变量应该是公开的。这是因为将变量公开不静止会导致它们不受欢迎。假设您有一个开发人员不小心使用公共变量。然后,他从另一类访问一个变量,没有意义来改变它。现在,由于这种不幸,他的软件有错误。这就是为什么我相信适当使用Getters和Setter的原因,但是您不需要每个私人或受保护的变量。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top