代码之家  ›  专栏  ›  技术社区  ›  Ben McCormack

为什么许多开发人员反对在OOP中使用“protected”修饰符?

  •  11
  • Ben McCormack  · 技术社区  · 16 年前

    我的一个同事正在参加一个考试 面向对象程序设计概论

    为什么许多开发人员反对在类上/类内使用“protected”modifier?

    当这个问题在午餐时被提出来时,我和我的同事都想不出为什么会有人这样做 使用 protected 受保护的

    就我个人而言 类上的访问修饰符是指当我编写了可能需要在测试环境中补充的代码时。例如,我可能编写一个没有调试信息的基类,然后创建一个新类进行测试,从基类继承并覆盖其方法,以便在基类方法调用之前/之后添加调试输出代码。我想我也可以很容易地使用一个包含接口和依赖注入的设计来实现相同的目标,但这是我唯一的经验 受保护的 已用于测试目的。在这种情况下,避免 受保护的 是因为你可以用更好的方式完成同样的事情。

    为什么开发者会反对使用 受保护的 他们OOP设计中的修改器?

    注意:因为教授问的是一个一般的面向对象的问题,而不是特定于任何一种语言,所以我不确定答案的权重是否会因为语言的不同实现而有所不同 在C#、Java等语言中。。

    12 回复  |  直到 16 年前
        1
  •  17
  •   dthorpe    13 年前

    开发人员不会抱怨保护措施,直到他们阻止开发人员获得他们想要使用的东西。对于正在创建子类的开发人员来说,protected没有什么大不了的,因为他们可以从子类中访问商品。

    对于那些 使用 一个给定的类(不是扩展它),受保护的块访问潜在的丰富的内部实现细节。这就是他们会抱怨的。

    1. 更新后的框架会更改代码所依赖的实现细节,并且代码会中断
    2. 设计者意识到他们不能在不破坏大量代码的情况下更改实现,所以他们选择不实现有用的特性或错误修复。这就是所谓的代码瘫痪。

    我曾在(不,是书面的)框架中工作过,在这些框架中,使用该框架的开发人员抱怨它对内部细节不够宽容。这些人抱怨说,即使修复了bug,添加了特性,并在各种平台迁移中重写了实现,但公共的、受支持的接口、代码契约仍然保持稳定,他们的代码基本上没有受到影响。

    因此,简而言之,开发人员会抱怨受保护(和私有)的访问修饰符,因为它妨碍了开发人员认为最简单、最快的解决方案实现方式,而忽略了依赖这些实现细节的未来成本。

        2
  •  6
  •   just somebody    14 年前

    因为对象交互优于继承。

    据报道,jamesgosling说,如果他再做一次Java,他就不用类了,并澄清了他所说的“类”的意思 继承 . protected 无意义的 private )没有继承(虽然不是在Java中),但是 公众的 退化,在Java中更是如此( Programming Scala chapter 5 ).

    图案上的Holub 这是一本Java的书,但是从面向对象的角度来看非常棒) 是 public 用另一个名字,特别是在Java中。一 符号是一个不能被信任的符号,它是在声明它的类中看到的。其他类(子类)可以在您的鼻子底下交换它。你在处理溜溜球效应。

    受保护的 公众的 -只是。

        3
  •  4
  •   jkerian    16 年前

    没有广泛的轮询,我只是猜测一下,这里主要讨论应用于成员函数的受保护修饰符。

    我怀疑是因为 protected: 在类成员上显式允许未来用户修改类行为。一般来说,这是很难计划的。问题在于你要处理和记录多少未知数。

    如果您的库允许子类重写受保护的方法,那么您必须注意,受保护方法的每个调用对于不熟悉库的特定要求的程序员来说都是安全的。这需要仔细的文档,而且目前还没有一个好的方法来限制流行语言的使用。

        4
  •  4
  •   KeithS    14 年前

    第一, protected 不保证隐私,除非继承链中唯一的可消费类是密封的(即所有基类都是程序集内部的)。任何了解OOP的开发人员都可以派生您的类,并将您的所有内部构件公开给世界。

    使用 internal 相反,在成员上通常可以解决这个问题;只有位于正在开发的同一程序集中的代码才能看到内部成员。您公开供其他人使用的公共子级可以从程序集外部派生,但是您希望隐藏的内部仍然是隐藏的。在同一程序集中创建子对象或其他对象的开发人员应该与您交流他们正在使用什么,如果从运行时的角度来看,您的内部构件确实是那么敏感的话。记得吗 protected internal 指受保护的或内部的,不受保护的和内部的。

    其次, 通常表示类设计中存在一些缺陷,特别是同时使用protected和public时。如果你有一个秘密,但你必须与你的孩子分享,这不是什么秘密,可能应该公开。如果这真的是个秘密,你的孩子不应该被信任,因为除非你给你的孩子做了输精管切除术 sealed 关键词,你不能阻止他们告诉他们的孩子,他们可能不再认为这是一个很大的秘密,并分享给他们的家人或世界。

    使用 这并不可怕,它只是没有实现许多开发人员想要使用它的目的;使“受信任”的个人可以访问类的内部,而不冒暴露微妙的内部进程的风险。它的访问控制更少,访问建议更多;通过使用protected,您说明此方法对儿童有用,但它本身对非儿童没有多大好处,或者如果暴露和误用,将对类有害。这就像在你的前院张贴一个牌子,上面写着“我的门锁上了,我不会给你钥匙,但我所有的孩子都有一把”。这还不算一半,因为一个“窃贼”可以让你的一个孩子来开门。

    一种常见的、被广泛接受的用法 受保护的 on方法是用于模板方法类的;这些抽象类具有公共框架工作流,但允许或需要扩展其功能的特定部分才能发挥作用。这些功能通常具有高度的内聚性和次要性。该模式将公开一个公共的、非虚拟的“驱动函数”,并将几个句柄作为受保护的抽象或虚拟方法提供给“助手”。这允许使用者派生类并实现helpers。

    在这种情况下,您通常不关心子实现,也不想限制可能的解决方案;子方法可能需要helper方法的公共包装器,以便与其依赖项通信。

    也是单元测试类内部的最直接的方法。单元测试是一件好事,但是如果您想编写一个测试夹具来执行一个方法,那么该方法必须可以从类外部访问。私底下是绝对不行的。内部通常会出现类似的问题。为了允许内部测试,它们必须至少受到保护,这样您就可以派生类来公开内部。否则,您需要一些真正的oogly反射来提取私有方法的MethodInfo并调用它(以及SkipVerification CAS权限)。

        5
  •  3
  •   Igor Zevaka    16 年前

    过度使用 protected 可能导致违反 ( 我 PDF link . 该原则指出,类的编写方式应该是任何子类都可以替换其基类。罗伯特·C·马丁在书中对此进行了很好的讨论 Agile Principles, Patterns, and Practices in C# 子类型 可替代的 对于它的基类来说,不仅仅是有一种关系。

    因此,通过受保护的方法公开过多的功能,您可能会允许子类过多地放松不变量,从而使子类不是真正的子类型。

    受保护的 应该/不应该使用。有些情况下,这是真正必要的,有些情况下,这不是。在个别情况下使用判决是必需的。

        6
  •  3
  •   Robert Harvey    16 年前

    封装被认为是一种很好的实践,通过使成员受到保护,可以打破封装,因为子类可以直接修改变量。

        7
  •  1
  •   Colin Hebert    16 年前

    对于受保护的字段/方法,子类依赖于父类的内部结构,这对耦合非常不利。这是一种说“我有一个‘私有’方法/字段,但是我的子类可以使用它”,更糟糕的是“可以重写/修改它”。

    这并不是我的观点,但我可以理解有些开发人员发现 protected 很难使用。


    资源:

        8
  •  1
  •   Steve Jessop    16 年前

    protected 成员导致类有两个接口:一个用于选择不子类化的客户机,另一个用于选择子类化的客户机。 受保护的 public 某物 ,但他们只为某些客户这样做。

    有时候这才是您真正想要做的:您已经为两个不同的用例仔细地设计了两个接口。抽象类可能属于这一类:您有使用 protected+public 界面和“用户”仅使用 公众的 接口。可能有一些用户不需要的有用功能可以提供给实现者,也可能有一些用户不需要的配置,但是实现者必须进行设置。使用受保护的方法执行此操作,只需为某些工厂定义一个单独的接口以返回“用户”。所以我不认为这是有害的,尽管它可能被认为有点古怪,因为它不是定义两个接口的“正常”方式。

    不过,当你使用 受保护的 事实上,当代码恰好是一个子类时,您并没有破坏封装。如果某件事“应该”是 private ,然后就成功了 受保护的 正在破坏您最初想要的封装。坏接口仍然是坏接口,不管它是呈现给世界还是仅仅呈现给子类。就这一点而言,任何一个不在街上的人都有可能将你的类划分为子类。所以即使是“只对子类”也不是很严格-你的错 受保护的 界面离 公众的 -它似乎通过限制谁看到它来扫除地毯下的邪恶,但实际上它没有。

    避免受保护的唯一原因是 因为你也能做到 以更好的方式处理事情。

    这还不够吗?把事情做得更好是。。。更好;-)

        9
  •  1
  •   supercat    16 年前

    “Protected”的一个原因是类在它的契约中包含对类来说是真实的,但对派生类来说不一定是真实的东西可能是有用的。在Liskov替换原则下,任何可以通过公共接口与Q类型的对象进行的操作,对于任何类型继承Q的对象都应该是可行的。因此,Q不应该公布任何在Q的某些派生下可能不存在的能力。

    从基类型派生的密封类(仅支持使用受保护的方法进行克隆)可以确定其类型的任何对象都支持克隆。即使班级没有封号,除非有人 不当 从它派生一个不支持克隆的类,派生类中的代码可以确定它将只用于可以克隆的对象。

    相比之下,使用传入的基类型对象执行操作的类在编译时无法知道它所提供的对象是否支持克隆。公开较低级别的克隆方法会导致在不支持它们的情况下调用它们。

        10
  •  1
  •   卢声远 Shengyuan Lu    16 年前

    因为受保护的是 它的子类是公共的 ,它是子类的API。对于客户端来说,它看起来像许多公共方法。

        11
  •  0
  •   emory    16 年前

    如果您正在开发单个包应用程序,并且您不希望它被扩展(它不是库),那么最好使用默认的修饰符-package private。

    如果您正在开发一个多包应用程序,那么您可能需要protected修饰符来允许贝塔。儿子调用阿尔法。父亲超类构造函数(但是阿尔法。父亲构造函数不可用)。 我将在没有证据的情况下推测开发人员更喜欢单包应用程序。

        12
  •  0
  •   Alex    16 年前

    有一条规则……“除非你有充分的理由不这样做,否则就用私人的” 你必须考虑是否有人会使用你的包/类并决定真正需要什么。 我从不使用protected,除非我要将lib发布给其他人,而且只有在需要时才使用。