类字段/属性/属性的可见性private是否有用?在OOP中,迟早要创建一个类的子类,在这种情况下,最好能理解并能够完全修改实现。

我要做的第一件事当我子类化一个类时,要做的是将一堆private方法更改为protected。但是,从外部世界隐藏细节很重要-因此我们需要protected而不是public

我的问题是:您是否知道private而不是protected是一个很好的工具的重要用例,还是两个选项“ protectedpublic”对于OOP语言就足够了?

评论

为什么“清洁代码”建议避免使用受保护的变量?

致低俗人士:尽管我也强烈反对OP的前提,但我赞成这个问题,因为它完全连贯,值得回答。是的,需要告诉操作人员为什么这是错误的,但是这样做的方法是写一个答案(或建议对现有答案进行编辑),而不是仅仅因为他还没有自己想出答案就投票。 br />
派生类是外部世界的一部分。

不要忘记,protected并不总是意味着访问被锁定到继承层次结构。在Java中,它还授予程序包级别的访问权限。

我的教授曾经说过:“有些事情我不会告诉我的孩子。那些事情我是我的私人领域。”

#1 楼

因为正如您所说,protected仍然使您能够“完全修改实现”。它并不能真正保护班级内部的任何东西。

为什么我们要关心“真正地保护”班级内部的东西?因为否则,在不破坏客户端代码的情况下更改实现细节是不可能的。换句话说,对于写原始基类的人来说,写子类的人也是“外部世界”。

实际上,protected成员本质上是类的“子类的公共API”,而需要保持稳定和向后兼容,就像public成员所做的一样。如果我们没有创建真正的private成员的能力,那么实现中的任何内容都将永远无法安全更改,因为您将无法排除(非恶意)客户端代码以某种方式成功依赖的可能性

顺便说一句,虽然“在OOP中,迟早要创建一个类的子类”在技术上是正确的,但您的论点似乎是在做出一个更强有力的假设,即“很快或以后,您将为每个类创建一个子类”,这几乎肯定不是这种情况。

评论


如果可以的话,我会向您扔超过+1,因为这是我第一次真正对我有意义。 lib透视图需要更频繁地使用,否则任何喜欢(类似C的)“绝对控制,绝对责任”的编码心态的人都可能将其标记为“保护我自己不受保护”。请注意,我以前仍然使用private,只是一直感觉很好的文档和类似_foo的命名约定表明您可能不应该搞混它,即使不是更好。能够确定地说“什么都不会破坏”是一项合法的,仅供私人使用的功能。

– abluejelly
16年3月11日在22:13

我最初忽略了公共库和框架的代码情况,而或多或少只考虑了“客户端代码”。优化内部实现是我的问题的一个很好的例子,尽管我问自己,这是否真的发生(特别是当许多人建议一个类的长度不应超过1000行代码时)。通常,我喜欢Ruby的方法,在这种方法中,私有是一种建议:“这是龙,请谨慎行事”。

–亚当·里布沙(AdamLibuša)
16-3-13在19:02



@AdamLibuša虽然如果您的代码是公开的,这是一个更大的交易,但即使您是该类所有客户的作者,它仍然适用。问题只是从不可能的某些重构变为乏味且容易出错的某些重构。在我的经验中,优化实际上是进行这些重构的最不常见的原因(尽管我主要使用Javascript),通常它更像是一个暴露了基本实现缺陷的错误,该缺陷需要重构各个内部位的依赖关系/调用图才能实现一个真正强大的修复程序。

– Ixrec
16-3-13在19:11

““迟早要为每个类创建一个子类”几乎肯定不是这种情况。”更重要的是,您几乎肯定不会,并且您也绝对不应覆盖类中的每个函数,并更改类中每个数据元素的用法。从逻辑上讲,有些事情应该用石头写成全书,以便让该类具有任何含义。

–杰伊
16-3-14的4:34

如果可以的话,我会给你扔超过+1 =>这就是我们所说的赏金@abluejelly

–托马斯·阿尤布(Thomas Ayoub)
16年3月18日在9:51

#2 楼


迟早要在OOP中创建类的子类。


,这是错误的。并非每个类都应该被子类化,某些静态类型的OOP语言甚至具有阻止它的功能,例如final(Java和C ++)或sealed(C#)。


很好了解并能够完全修改实现。


不,不是。对于一个类来说,即使它是继承自它的,也能够清楚地定义其公共接口并保留其不变性,这是一个好习惯。

通常,访问控制是关于分隔的。您希望理解代码的单个部分,而不必详细了解它如何与其余代码交互。私人访问允许。如果至少所有内容都受到保护,则您必须了解每个子类的操作才能了解基类的工作方式。

或用Scott Meyers的话来说:类的私有部分是受有限数量的代码(类本身的代码)影响。

公共部分可能受到存在的每一位代码以及尚待编写的每一位代码的影响,这是无限的。代码量。

受保护的部件可能会受到每个现有子类以及每个尚待编写的子类的影响,这也是无限数量的代码。

结论是受保护的内容比公共的内容少得多,而私有的则为您带来真正的进步。受保护的访问说明符的存在是有问题的,而不是私有的。

评论


对于“受无限数量的代码影响”的理论场景,+ 1

–Broken_Window
16年3月11日在13:53

也许还值得注意的是,出于此答案中概述的原因,C#设计人员实际上决定禁止重写继承的方法,除非将其显式标记为虚拟方法。

–威尔登(Will Vousden)
16年3月11日在15:05

或简单地说:protected适用于方法,而不适用于数据成员。

– Matthieu M.
16年3月11日在15:35

我现在找不到它,但是我记得从@EricLippert读了一个写得很好的答案,内容涉及为什么MS密封.net库的大部分内容以及IIRC为什么他希望将其余部分锁起来。当您允许第三方继承者开始使用内部值时,您需要为每种方法添加大量的验证/健全性检查,因为您不再信任有关对象内部状态的任何设计不变式。

–丹在火光中摆弄
16年3月11日在16:05

@ThorbjørnRavnAndersen“正在开发中,但没有发布时”-班上到底应该怎么知道?当您甚至无法测试发行版本时,您真的要编译与发行版本不同的测试版本吗?无论如何,测试都不需要访问私有内容。

–塞巴斯蒂安·雷德尔(Sebastian Redl)
16-3-14在7:51

#3 楼

是的,私有字段是绝对必要的。就在这周,我需要编写一个自定义词典实现,在其中我控制了放入词典中的内容。如果将字典字段设置为受保护或公共的,那么我精心编写的控件可能很容易被规避。

私有字段通常用于提供保护措施,确保数据与原始编码器相同预期。使所有东西都受到保护/公开,然后您通过这些程序和验证来骑马训练。

评论


+1代表“骑马和骑马”。我希望我能听到更多这句话。

–莫妮卡基金的诉讼
16 Mar 11 '16 at 19:38

如果有人需要继承您的班级,也许他应该可以使用您的保障措施?而且,如果您不希望有人更改保护措施以实现某个目标,也许不共享代码?在Ruby中,它的工作原理是这样-私有或多或少是一个推荐。

–亚当·里布沙(AdamLibuša)
16年3月12日在10:05

@AdamLibuša“不共享代码”?一旦发布了所有DLL,就在共享代码-所有结构和方法以及所有内容都可以在全世界看到,特别是使用默认支持反射的语言。每个人都可以使用“您的代码”做任何想做的事情-私有只是说“别碰这些”的一种方式,并且可以在编译器合同中强制执行。在.NET之类的系统中,这也具有重要的安全隐患-只有获得完全信任(基本上等同于admin / root访问权限),您才可以触摸他人的私人用户。

–罗安
16年3月14日在9:06

@AdamLibuša我认为您的困惑主要源于不同语言所采用的不同的OOP方法。 OOP(最初定义)的根源是消息传递-这意味着,除了您响应的消息之外,所有内容都是私有的。在大多数OOPish语言中,这被公开为“使数据保持私密”-一种使公共接口尽可能小的方法。用户(无论是子类还是其他类)必须操作您的类的唯一方法是通过定义的公共界面-类似于通常使用方向盘和踏板驾驶汽车的方式:)

–罗安
16年3月14日在9:09

@Luaan +1可以联系其他人的私人物品!

–奈杰尔Touch
16年3月14日在14:30

#4 楼

当试图正式地推理面向对象程序的正确性时,通常使用涉及对象不变式的模块化方法。用这种方法


方法将它们与前后条件(合约)相关联。
对象与它们的不变量相关联。

关于对象进行如下操作(至少首先近似)


证明对象的构造函数建立不变性
对于每个非私有方法,假定对象不变且方法先决条件保持输入,然后证明代码主体暗含方法退出的后置条件和不变保持力

想象一下我们使用上述方法验证了object A。现在希望验证method gobject B,它调用method fobject A。模块化推理使我们能够对method g进行推理,而不必重新考虑method f的实现。假设我们可以在object A的调用站点建立method f的不变量和method g,的前提,则可以将method f的后置条件作为方法调用行为的摘要。此外,我们还将知道在调用返回之后,A的不变式仍然成立。

这种模块化的推理功能使我们可以正式思考大型程序。我们可以分别对每种方法进行推理,然后将推理的结果组合起来,进而对程序的更大部分进行推理。

私有字段在此过程中非常有用。为了知道对象的不变性在该对象的两个方法调用之间继续保持不变,我们通常依赖于以下事实:在此期间对象没有被修改。

为了使模块化推理能够在对象没有私有字段的情况下工作,那么我们将必须有某种方法来确保无论哪个字段碰巧被另一个对象设置,都必须始终重建不变式(在字段之后组)。很难想象一个对象不变式既持有该对象字段具有的任何值,又在推理程序的正确性时很有用。我们可能必须发明一些有关现场访问的复杂约定。可能还会失去部分(甚至是全部)模块化推理的能力。

受保护字段

受保护字段恢复了我们进行模块化推理的能力。根据语言,protected可能会限制将字段设置为所有子类或所有子类和相同包装类的功能。通常情况下,当我们在思考所编写对象的正确性时,我们无法访问所有子类。例如,您可能正在编写一个组件或库,以后将在一个较大的程序(或几个较大的程序)中使用-其中某些甚至可能尚未编写。通常,您不知道是否可以将其子类化以及以何种方式对其进行子类化。

通常,子类通常有责任维护其扩展类的对象不变性。因此,在一种语言中,保护仅表示“子类”,并且我们受到纪律以确保子类始终保持其父类的不变量,因此您可能会争辩说,使用受保护而不是私有的选择只会损失最小的模块化。

尽管我一直在谈论形式化推理,但通常人们认为,当程序员非正式地思考其代码的正确性时,他们有时还依赖于类似类型的参数。

#5 楼

由于相同的原因,一个类中的private变量优于protected,原因相同,原因是break块中的switch语句优于goto label语句;这就是人类程序员容易出错。

protected变量很容易导致无意滥用(程序员错误),就像goto语句很容易创建意大利面条代码一样。

是否可以编写代码使用protected类变量的无bug代码?当然是!就像可以使用goto编写无错误的工作代码一样;但是俗话说得好:“只是因为您可以,并不意味着您应该!”

存在类,甚至是OO范式,可以防止易出错的人类程序员犯错误。防止人为错误的防御措施仅与班级内置的防御措施一样好。实施protected类等效于在堡垒的墙壁上凿出一个大洞。

基类完全不了解派生类。就基类而言,protected实际上没有提供比public更多的保护,因为没有什么可以阻止派生类创建行为类似于后门的public getter / setter。

如果基类允许不受阻碍地访问其内部实现细节,因此该类本身无法防御错误。基类绝对不了解其派生类,因此无法防范那些派生类中的错误。

基类可以做的最好的事情是尽可能隐藏其实现,并设置足够的限制以防止破坏派生类或该类之外的任何其他内容的更改。

最终,存在高级语言以最大程度地减少人为错误。还存在良好的编程习惯(例如SOLID原理),以最大程度地减少人为错误。

忽略良好编程习惯的软件开发人员,失败的可能性更高,并且更有可能产生无法维护的解决方案。遵循良好实践的人失败的可能性要低得多,并且更有可能产生可维护的可行解决方案。

评论


拒绝投票-此答案可以更改/改进什么?

–本·科特雷尔
16-3-11在19:20



我没有拒绝投票,但是将访问级别与中断/转到进行了比较?

– imel96
16年3月14日在9:36

@ imel96不,比较为什么避免使用它们的原因,并因“最佳实践”而灰心(尤其是编写新代码时)。即,有能力的程序员会避免公开实施细节,因为它使自己难以维护的代码成为可能。有能力的程序员会避免使用goto,因为它会使自己无法维护的代码。但是,现实世界是如此,有时您会迷失在糟糕的旧代码中,别无选择,只能使用goto,并且出于同样的原因,有时您别无选择,只能使用公共/受保护的实现细节。

–本·科特雷尔
16-3-14在9:46



严重性在大小上是不同的,这是无与伦比的。我可以只使用具有公共属性/接口的代码,而不能只使用goto的代码。

– imel96
16-3-14在10:33

@ imel96您是否曾经真正在使用goto的代码中工作,或者仅仅是因为您已经阅读过类似的文章?我了解goto为什么是邪恶的,因为我花了2年的时间在使用它的古老代码中工作;而且我花了更长的时间编写代码,在这些代码中,“类”的实现细节随处可见,而公共和朋友说明符被用作快速/轻松/肮脏的骇客。我不接受这样的论点,即“公开公开实现细节”不会导致像goto一样严重的意大利面条混乱,因为它绝对可以。

–本·科特雷尔
16-3-14在18:51

#6 楼

可继承的类有两个协定-一个带有对象引用的持有者,另一个带有派生类。公有成员受参考持有人的合同约束,受保护成员受衍生类的合同约束。

使成员protected使其具有更多用途的基类,但通常会限制其使用方式该类的将来版本可能会更改。使成员成为private可以使类作者具有更多的通用性来更改类的内部工作方式,但限制了可以从其派生的类的种类。

例如,.NET中的List<T>使私人后备店;如果受保护,派生类型可能会做一些有用的事情,而这些事情原本是不可能的,但是List<T>的未来版本将永远不得不使用笨拙的整体式后备存储,即使对于包含数百万个项目的列表也是如此。将后备存储设置为私有将允许List<T>的未来版本使用更有效的后备存储,而不会破坏派生类。

#7 楼

我认为在您的论点中有一个关键的假设,即当某人编写课程时,他们并不知道谁可能会扩展该课程以及出于何种原因。在这种假设下,您的论点将是非常合理的,因为您私有的每个变量都可能会切断未来的发展途径。但是,我会拒绝这个假设。

如果该假设被拒绝,那么只有两种情况可以考虑。


原始类的作者对于为什么可以扩展它有非常清晰的想法。 (例如,这是一个BaseFoo,并且将来会有几个具体的Foo实现)。

在这种情况下,作者知道有人会扩展该类以及原因,因此确切地知道该怎么做。使受到保护以及使什么私有化。他们使用私有/受保护的区别向创建子类的用户传达各种接口。


子类的作者正试图将某些行为破解到父类中。

这种情况应该很少见(您可能会认为这是不合法的),并且不建议仅在原始代码库中修改原始类。这也可能是不良设计的征兆。在这种情况下,我宁愿以这种方式入侵的人只使用其他黑客(例如,朋友(C / C ++)和setAccessible(true)(Java))。

我可以肯定地拒绝该假设。

这通常会归结为继承而不是继承的想法。继承通常被认为是减少代码重用的理想方法,但是很少应该将其作为代码重用的首选。我没有简单的否定论点,理解起来可能相当困难且充满争议。但是,根据我在域建模方面的经验,我发现在很少清楚谁将继承我的类及其原因的情况下,很少使用继承。

#8 楼

所有这三个访问级别都有其用例,缺少它们的OOP将是不完整的。通常您会


将所有变量/数据成员设为私有。您不希望外部有人弄乱您的内部数据。同样为公共或受保护的接口提供辅助功能(根据几个成员变量进行计算的方法)的方法-仅供内部使用,您将来可能希望对其进行更改/改进。
创建通用接口您的班级公众。那就是原始类的用户应该使用的东西,以及您认为派生类也应该是什么样子。为了提供适当的封装,这些通常只是方法(以及帮助程序类/结构,枚举,typedef,无论用户需要使用哪种方法来使用它们),而不是变量。
声明受保护的方法可以用于想要扩展/专业化类功能但不应该成为公共接口一部分的人-实际上,您通常会在必要时将私有成员提升为受保护的成员。如果您不确定,除非您知道


您的类可以/可以/将被子类化,
并清楚地知道子类的用例可能是什么



只有在有充分理由的情况下,您才偏离此一般方案。提防“当我可以从外部自由访问它时,这将使我的生活更轻松”(并且这里也包括子类)。当我实现类层次结构时,我通常从没有受保护成员的类开始,直到我对它们进行子类化/扩展/专业化,成为框架/工具包的基类,有时将其原始功能的一部分上移。

#9 楼

也许一个更有趣的问题是,为什么除了私有之外,还需要其他任何类型的字段。当子类需要与超类的数据进行交互时,这样做可以直接在两者之间建立直接耦合,而使用提供二者之间交互的方法可以实现一定程度的间接访问,从而可以对父类进行更改。

许多语言(例如Ruby和Smalltalk)不提供公共字段,因此不鼓励开发人员直接将其耦合到其类实现,但为什么不走得更远而且只有私人领域?不会失去一般性(因为超类始终可以为子类提供受保护的访问器),但是它将确保类始终与子类至少保持很小的隔离度。为什么这不是更常见的设计?

#10 楼

这里有很多不错的答案,但是无论如何我都会投入两分钱。 :-)

私有是好的,其原因与全局数据不好的原因相同。

如果一个类将数据声明为私有,那么您绝对会知道唯一的代码与此混淆数据是该类中的代码。出现错误时,您无需在整个创建过程中进行搜索,只需查找可能会更改此数据的每个位置。您知道它在课堂上。当您更改代码并更改有关如何使用此字段的内容时,您不必跟踪可能使用此字段的所有潜在位置,也不必研究计划的更改是否会破坏它们。您知道唯一的地方在类中。

我不得不多次更改库中并由多个应用程序使用的类,因此我不得不非常小心,以确保我不会破坏我一无所知的应用程序。公开和受保护的数据越多,出现问题的可能性就越大。

#11 楼

我认为值得一提一些不同意见。

从理论上讲,出于其他答案中提到的所有原因,最好控制访问级别。

在实践中,经常出现在检查代码时,我看到人们(喜欢使用私有的)正在将访问级别从私有->受保护的更改为访问级别,而不是从受保护的->公共更改访问级别。几乎总是,更改类属性涉及修改setter / getter。这些浪费了我很多时间(代码审查)和他们的时间(更改代码)。

让我烦恼的是,这意味着它们的类没有被关闭以进行修改。

与内部代码一起使用,您可以在需要时随时对其进行更改。当第三方代码很难更改代码时,情况就更糟了。

那么有多少程序员认为这很麻烦?那么,有多少人正在使用没有私有语言的编程语言?当然,人们不仅使用这些语言是因为它们没有专用的说明符,而且还有助于简化语言,并且简单性很重要。

Imo它与动态/静态类型非常相似。从理论上讲,静态类型非常好。实际上,它只能防止2%的错误。动态键入的不合理效果....使用private可能会防止错误的发生。

我认为SOLID原则很好,我希望人们更关心它们,而不是关心创建具有公共,受保护和私有的类。

评论


如果在使用时需要更改第三方代码,则要么设计得不好,要么使用得不好。您始终可以通过封装重用非抽象类,但实际上,您几乎不需要对其进行子类化。

–小桑蒂
16 Mar 16 '16 at 23:26

#12 楼

我还想补充一个实际的示例,说明为什么protected不够用。在我的大学里,最初的几年从事一个项目,他们必须开发桌面版的棋盘游戏(后来开发了AI,并通过网络将其连接到其他玩家)。提供了一些部分代码以使他们开始使用它们,包括测试框架。主游戏类的某些属性公开为protected,以便扩展该类的测试类可以访问它们。但是这些字段不是敏感信息。

作为单位的技术支持,我经常看到学生简单地编写所有添加的代码protectedpublic(也许是因为他们看到了其他protectedpublic东西,并认为他们应该照做)。我问他们为什么他们的保护水平不合适,许多人不知道为什么。答案是,他们暴露给子类的敏感信息意味着其他玩家可以通过简单地扩展该类并访问游戏的高度敏感信息来作弊(本质上是对手的隐藏位置,我想这类似于如果您可以通过扩展某些班级在战舰板上看到对手的碎片)。这使他们的代码在游戏环境中非常危险。

除此之外,还有许多其他原因可以使某些内容甚至您的子类保持私有。可能是隐藏实现细节,如果某些人不一定知道他们在做什么,则可能会改变类的正确工作(大多数情况是在这里考虑使用您的代码的其他人)。

评论


我不明白除非玩家在游戏运行时动态扩展类,否则如何用它来作弊?这意味着您正在将不受信任的代码导入您的代码库。如果您要说给学生们上编译课,并通过修改实施细节来防止他们作弊,那么设置保护级别将不会使任务更加安全。学生可以对库进行反编译或利用反射来发挥自己的优势。当然,这取决于您追求的执行水平。

–山姆
16年3月13日在0:30

@sam通常,在编写代码时应假定下一个修改该代码的人不必完全了解整个代码库。有时甚至可能是原始作者(时间流逝,缺乏睡眠...)。作弊可能是给学生们充实的骨架代码,并改变了他们不应该碰到的逻辑。

– Phil Lello
16年3月16日14:17



#13 楼

私有方法/变量通常将从子类中隐藏。这可能是一件好事。

私有方法可以对参数进行假设,并向调用方进行完整性检查。

受保护的方法应该对输入进行完整性检查。 >

#14 楼

“私有”是指:除类本身之外,任何人都不得更改或访问。不打算由子类更改或访问。子类?什么子类?您不应该对此子类化!

“受保护”的意思是:仅打算由类或子类更改或访问。可能推论您应该继承,否则为什么要“受保护”而不是“私有”?

这里有明显的区别。如果我将某些内容设为私人,则应该避免弄脏您的手指。即使您是子类。

#15 楼


当我将一个类子类化时,我要做的第一件事就是将一堆私有方法更改为protected


关于privateprotected方法的一些理由:

private方法可防止代码重用。子类不能使用私有方法中的代码,而可能不得不再次实现它-或重新实现最初依赖于私有方法&c的方法。

另一方面不是private的方法可以看作是该类提供给“外部世界”的API,从某种意义上讲,第三方子类也被视为“外部世界”,正如其他人已经在其答案中建议的那样。 >
这是一件坏事吗? -我不这么认为。

当然,(伪)公共API会锁定原始程序员,并阻碍这些接口的重构。但是反过来,为什么程序员不应该像公共API一样干净,稳定地设计自己的“实现细节”呢?他是否应该使用private以便草率构造“私有”代码?想也许他以后可以清理,因为没人注意到吗? -否。

程序员也应该在他的“私有”代码中加些思考,以便以允许甚至促进尽可能多地重用它的方式来构造它。这样,将来非私有部分可能就不会像有些恐惧那样成为负担。

我看到很多(框架)代码采用private不一致的用法:protected,最终的通常会发现除了授权给私有方法外几乎不做任何其他事情的方法。 protected,非最终方法,其合同也只能通过直接访问私有字段来实现。

这些方法在逻辑上不能被覆盖/增强,尽管从技术上讲,没有什么可以使(编译器)显而易见的。

需要可扩展性和继承性吗?不要让您的方法private

不希望更改类的某些行为?将您的方法设为final。真的不能在定义明确的特定上下文之外调用您的方法吗?使您的方法private和/或考虑如何通过另一种protected包装器方法使所需的定义明确的上下文可重用。

这就是为什么我提倡谨慎使用private的原因。并且不要将privatefinal混淆。 -如果方法的实现对于类的总协定至关重要,因此不能替换/重写,请使其成为final

对于字段而言,private确实不错。只要可以通过适当的方法(不是getXX()setXX()!)合理地“使用”该字段,那么

评论


-1这没有解决私有与受保护的原始问题,给出了错误的建议(“谨慎使用私有”吗?)并且违背了关于OO设计的普遍共识。使用private与隐藏草率代码无关。

– Andres F.
16 Mar 11 '16 at 19:24



您提到了一个类具有一个API,但似乎并没有使该API用户不想被他们不需要知道的细节所困扰。对于类用户而言,理想的情况是接口只包含他们需要的方法,而不包含其他任何方法。将方法设为私有有助于保持API的清洁。

–本·科特雷尔
16-3-11在19:33



@HannoBinder我同意那里有很多类都遭受了刚性的困扰,但是灵活性和代码重用性远不如封装和长期可维护性重要。考虑一下您的情况,其中所有类都有受保护的成员,而派生类可能会弄乱他们想要的任何实现细节;您如何可靠地对那些类进行单元测试,从而知道尚未编写的代码的任何部分中的任何内容都可能随时导致该代码失败?在所有代码都退化成一个大泥巴之前,代码可以采取多少个这样的“ hacks”?

–本·科特雷尔
16年3月12日在15:49

哦,你说的是“成员”。我的意思是仅指方法。成员变量(字段)是一个不同的故事,其中隐私更为合理。

– JimmyB
16 Mar 12 '16 at 18:12

讨论中的术语遍布各处,因为它不是特定于特定语言的。 C ++中的“成员”可以是数据,函数,类型或模板。

–JDługosz
16年3月12日在21:05

#16 楼


您是否知道一个重要的用例,其中私有而不是
protected是一个很好的工具,或者两个选项“ protected&public”对于OOP语言是否足够?


私有:当您拥有对任何子类都无法使用的东西进行调用或覆盖时。

受保护:当您拥有某些具有特定于子类的实现/常量的东西。

示例:

public abstract Class MercedesBenz() extends Car {
  //Might be useful for subclasses to know about their customers
  protected Customer customer; 

  /* Each specific model has its own horn. 
     Therefore: protected, so that each subclass might implement it as they wish
  */
  protected abstract void honk();

  /* Taken from the car class. */
  @Override
  public void getTechSupport(){
     showMercedesBenzHQContactDetails(customer);
     automaticallyNotifyLocalDealer(customer);
  }

  /* 
     This isn't specific for any subclass.
     It is also not useful to call this from inside a subclass,
     because local dealers only want to be notified when a 
     customer wants tech support. 
   */
  private void automaticallyNotifyLocalDealer(){
    ...
  }
}


评论


当您拥有对任何子类都无法使用的东西进行调用或覆盖时–我认为这是您事先不知道的。

–亚当·里布沙(AdamLibuša)
16-3-18在13:02



好吧,我可能还需要按CMOS上的Reset按钮。但是默认的假设是我真的不需要它,因此将其放在机箱中。方法也一样。如果子类绝对需要重新实现/调用它,则可以使其受到保护(请参阅:鸣喇叭)。如果其他各方需要调用它,则将其公开。

– Arnab Datta
16年3月18日在23:15

#17 楼

我很难理解这个问题,所以我想分享一下我的经验:


什么是受保护领域?它不过是一个字段,无法在类外访问,即像这样公开访问:$classInstance->field。而这就是“就是这样”的窍门。您班级的孩子们将有权使用它,因为这是他们应有的内部责任。
什么是私人领域?对于您自己的类和您自己的此类实现,它是“真正的私有”。就像放在药瓶上一样,“不要让孩子接触”。您将保证它不能被类的派生类覆盖,您的方法(在被调用时)将具有您声明的确切信息。

UPDATE:我已经解决的实际任务的实际示例。这就是:您有一个令牌,例如USB或LPT(在我的情况下),并且您有一个中间件。令牌要求您输入密码,如果密码正确,则会打开,您可以发送加密的部分和一些要解密的密钥。密钥存储在令牌中,您无法读取它们,只能使用它们。并且有用于会话的临时密钥,由令牌中的密钥签名,但存储在中间件本身中。临时键不应泄漏到外部,而应存在于驱动程序级别。我使用一个专用字段来存储此临时密钥和一些与硬件连接有关的数据。因此,没有派生工具不仅可以使用公共接口,还可以使用我为某项任务编写的某些受保护的“方便”子例程,但无法使用按键和硬件交互来打开保险箱。有道理吗?

评论


对不起大家!只是把他们搞砸了-更新我的答案=)谢谢!我很着急,打错了=)

–阿列克谢·韦斯宁(Alexey Vesnin)
16 Mar 11 '16 at 23:10

我认为OP意识到这两个保护级别之间的差异,但是对为什么要在另一个保护级别上使用它感兴趣。

–山姆
16 Mar 13 '16 at 0:32

@Sam请更深入地阅读我的答案。他们是完全不同的领域!它们唯一的共同点是它们都不能公开引用

–阿列克谢·韦斯宁(Alexey Vesnin)
16-3-13的1:18

我不确定您指的是什么。我知道私有和受保护之间的区别。也许您误解了保护等级的含义?我指的是“访问级别”。我试图指出,虽然您的回答还不错,但并不能直接解决问题。 OP似乎知道受保护的/私有的/公共的含义,但是不确定在什么情况下他们想选择一个。这可能是您被否决的方式(不是我)。

–山姆
16 Mar 13 '16 at 6:45

@Sam我想我明白您的意思-从我的实际实践/经验中添加了一个实际案例。这是您所缺少的吗?

–阿列克谢·韦斯宁(Alexey Vesnin)
16年3月13日在15:01