为什么有私有字段,保护不够?


265

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

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

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



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

18
派生类是外部世界的一部分。
CodesInChaos

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

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

Answers:


225

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

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

实际上,protected成员本质上是类的“子类的公共API”,并且需要保持稳定和向后兼容,就像public成员所做的一样。如果我们没有创造真正的能力private的成员,则没有在一个实现将永远是安全的改变,因为你不能就能够排除可能性(非恶意)客户端代码总算依靠它。

顺便说一句,虽然“在OOP中,迟早要成为一个类的子类”在技术上是正确的,但您的论点似乎是在做出一个更强的假设,即“迟早要成为一个子类的子类”。每个班级”几乎可以肯定不是这样。


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

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

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

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

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

256

在OOP中,迟早要创建一个类的子类

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

理解并能够完全修改实现是一件好事。

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

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

或用斯科特·迈耶斯(Scott Meyers)的话来说:类的私有部分受有限数量的代码(即类本身的代码)的影响。

公共部分可能会受到现有的每一位代码以及尚未编写的每一位代码的影响,这是无限数量的代码。

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

结论是,受保护比公共给您带来的收益更多,而私有给您带来了真正的进步。受保护的访问说明符的存在是有问题的,而不是私有的。


34
对于“受无限数量的代码影响”的理论情况,该值+1
Broken_Window

13
也许还值得注意的是virtual,出于此答案中概述的原因,除非明确将其标记为,否则C#设计人员实际上决定禁止重写继承的方法。
Will Vousden'3

11
或简单地说:protected是用于方法,而不是用于数据成员。
Matthieu M.

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

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

33

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

专用字段通常用于提供保护措施,以确保数据符合原始编码器的要求。使一切都受到保护/公开,您将通过这些程序和验证来骑马训练。


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

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

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

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

3
@Luaan +1可以触摸其他人的私人物品!
Nigel Touch

12

当试图正式推理关于面向对象程序的正确性典型的使用涉及模块化方法的对象不变。用这种方法

  1. 方法与条件(合同)的前后相关。
  2. 对象与它们相关联的不变量。

关于对象的模块化推理如下(至少首先近似)进行

  1. 证明对象的构造函数建立了不变式
  2. 对于每个非私有方法,假定对象不变式和方法前提条件在输入时成立,然后证明代码主体暗示后置条件和不变条件对方法的退出

想象一下,我们object A使用上述方法验证了。而现在希望验证method gobject B它调用method fobject A。模块化推理使我们method g无需重新考虑的实现即可进行推理method f。假设我们可以在调用站点建立的不变性object A和前提条件,method f那么method g,我们可以将的后置条件method f作为方法调用行为的总结。此外,我们还将知道,在调用返回后,A仍然保持不变。

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

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

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

受保护的领域

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

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

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


8

privateprotected出于相同的原因,一个类中的变量优于块breakswitchgoto label语句胜于语句。这就是人类程序员容易出错。

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

是否可以使用protected类变量编写有效的无错误代码?当然是!就像可以使用编写有效的无错误代码一样goto;但正如老话所说,“只是因为你可以,并不意味着你应该!”

存在类以及确实是OO范式,以防止不幸的易于出错的人类程序员犯错误。防止人为错误的防御措施仅与班级内置的防御措施一样好。实施课程protected相当于在堡垒的墙壁上凿出一个大洞。

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

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

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

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

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


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

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

@ imel96不,比较为什么避免使用它们,并因“最佳实践”而灰心(尤其是编写代码)。也就是说,有能力的程序员会避免public执行细节,因为它使自己无法维护代码。有能力的程序员会避免这样做,goto因为它使自己无法维护代码。但是,现实世界是如此,有时您会迷失在糟糕的遗留代码中,别无选择,只能使用goto,并且出于同样的原因,有时您别无选择,只能使用公共/受保护的实现细节。
Ben Cottrell

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

2
@ imel96您是否曾经真正使用过使用goto或仅因为阅读过此类文章的代码?我了解为什么 goto会邪恶,因为我花了两年时间在使用它的古老代码中工作;而且我花了更长的时间编写代码,其中“类”的实现细节在各处泄漏,public并且friend使用说明符作为快速/轻松/肮脏的骇客。我不接受这样的论点,即“公开公开实现细节”不会导致意大利面条混乱的严重程度达到goto绝对相同的程度。
本·科特雷尔

4

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

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

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


4

我认为您的论点中有一个关键的假设:当某人写某堂课时,他们不知道谁会继续上课,原因是什么。在这种假设下,您的论点将是非常合理的,因为您私有的每个变量都可能会切断未来的发展途径。但是,我会拒绝这个假设。

如果该假设被拒绝,则仅需考虑两种情况。

  1. 原始类的作者对于为什么要扩展它有非常明确的想法(例如,它是BaseFoo,并且在将来还会有一些具体的Foo实现)。

在这种情况下,作者知道有人会扩展该类及其原因,因此将确切知道要保护的内容和私有化的内容。他们使用私有/受保护的区别将各种接口传达给创建子类的用户。

  1. 子类的作者正试图以某种行为侵入父类。

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

我认为拒绝这个假设是安全的。

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


2

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

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

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


1

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

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


1

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

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

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

我已经有很多次不得不对库中的类进行更改,并且这些类被多个应用程序使用,而且我必须非常谨慎以确保不会破坏我一无所知的应用程序。公开和受保护的数据越多,发生故障的可能性就越大。


1

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

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

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

这也让我感到恼火,这意味着它们的类没有为修改而关闭。

那就是内部代码,您可以根据需要随时更改它。当第三方代码不那么容易更改代码时,情况更糟。

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

Imo与动态/静态输入非常相似。从理论上讲,静态类型非常好。在实践中,它只防止类似错误的2%,动态类型不合理的有效性...。使用private可能会减少错误。

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


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

0

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

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

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


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

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

0

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

私有方法可以对参数进行假设,并将健全性检查留给调用方。

一种受保护的方法应进行完整性检查输入。


-1

“私有”是指:除类本身以外,任何人都不得更改或访问。不打算由子类更改或访问。子类?什么子类?你不应该继承这个!

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

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


-1

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

关于privatevs protected 方法的一些理由:

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

在另一方面,这是任何方法不是 private可以看作是由类“外部世界”提供的API,在这个意义上的第三方子类被认为是“外面的世界”也一样,别人在他的回答提出已经。

那是一件坏事?-我不这么认为。

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

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

很多(框架)代码,我看到采用不一致的用途privateprotected,它几乎做任何事情比委托给私有方法更多的非最终方法是常见的。protected,其非最终方法的合同也只能通过直接访问私有字段来实现。

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

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

不想改变班上的某些行为吗?做你的方法final

真的不能在定义明确的特定上下文之外调用您的方法吗?使您的方法private和/或考虑如何使所需的定义明确的上下文可用于通过另一个protected包装方法重用。

这就是为什么我主张private谨慎使用。并且不要private与之混淆final。-如果方法的实现对于该类的总协定至关重要,因此不能替换/重写该方法,请使用它final

对于领域来说,private还算不错。只要可以通过适当的方法(不是 getXX()setXX()!)合理地“使用”该字段。


2
-1这没有解决privatevs protected原始问题,给出了错误的建议(“ private谨慎使用”吗?),并且与OO设计的一般共识背道而驰。使用private与隐藏草率的代码无关。
Andres F.

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

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

2
哦,你说的是“成员”。我的意思是仅指方法。成员变量(字段)是另一回事,隐私在其中更为合理。
JimmyB

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

-1

您是否知道一个重要的用例,其中私有而不是受保护是一个很好的工具,或者两个选项“受保护和公共”对于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(){
    ...
  }
}

2
当您拥有对任何子类都无法使用或调用的东西–我认为这是您事先不知道的。
亚当·里布沙(AdamLibuša)

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

-2

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

  • 什么是保护区?这是没有更多比一个领域,即不能在类的外部访问,即公开这样的:$classInstance->field。而这就是“就是这样”的窍门。您班上的孩子们将拥有全部使用权,因为这是他们合法的内部组成部分。
  • 什么是私人领域?对于您自己的类您自己的此类实现,这是一个“ 真正的私有 ” 。就像放在药瓶上一样,“不要让孩子接触”。你就有了保证,它是由你的类的衍生物,你的方法unoverridable -当所谓的-将有确切你声明什么

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


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

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

@Sam请更深入地阅读我的答案。他们是完全不同的领域!在只有他们的共同点是,他们都不能公开引用
阿列克谢维斯宁

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

@Sam我想我明白您的意思-从我的实际实践/经验中添加了一个实际案例。这是您所缺少的吗?
Alexey Vesnin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.