好的,为什么要这么做呢?因为这是它们存在的原因。也许你想知道为什么需要这样做。简单的回答是,派生类需要访问它们,而外部类不需要。
访问修饰符(除了public和protected,还有private、internal和protected internal)是尽可能使代码易懂以减少错误的一种方式。
有一些语言没有任何封装形式。在最极端情况下,任何代码都可以改变任何数据的任何部分。遵循规范的程序员会减少给定类型数据操作的数量,但可能仍然不清楚所有可能导致对象*处于不同状态的操作组合。当他们的代码作为别人的代码的一部分时,情况会变得更糟。
访问修饰符可以帮助我们解决这个问题。我们默认将成员设为私有。那么这个成员唯一能够访问的地方就是在类本身内。这意味着:
1. 操作中出现失误的唯一位置就在类内。
2. 唯一需要考虑如何保持这些成员处于一致状态的代码位于类内,而且该代码不必担心其他代码会干扰这一点。
3. 通过查看一个类的定义,我们可以获得这些字段被操作的所有方法的完整图片,这通常在一个文件中,并且很少超过两个文件。
这使我们更容易编写良好的代码。
当然,所有成员都是私有的类并不是很有用。通常我们需要让一些成员公开。通常我们的字段是私有的,有一些有用的方法也是私有的,然后一些公共方法和属性使用它们。虽然我们已经向其他类开放了调用执行此操作的成员,但仍然可以通过检查一个类来检查私有成员的所有可能操作。因此,这些成员为我们提供了在类内外部之间的界面,我们通过这个界面保护类的状态免受错误,同时为其他代码提供有用的功能。
现在应该清楚了,除非必须如此,否则我们不会将某些东西设为公共的,但我们确实需要这样做才能进行有用的工作。
将成员设置为protected会给我们带来一个折衷方案。我们仍在减少可以操作某些内容的位置,但不那么严格。通常,这是为了派生类可以为基类定义的一般接口提供自己的机制。
由于通常要么将东西保持私有(更安全),要么必须公开才能有用,因此使用情况较少。其中最常见的情况之一是,公共成员提供功能,而protected定义了实现该功能的方法。例如,HttpEncoder提供了几种处理编码HTML字符串问题的方法,但有两个受保护的抽象方法可以由派生类重写以提供多个不同方法所需的功能。外部类不需要访问这些方法,但派生类需要访问它们。
一个实际的例子。假设我们有一个实现了
INotifyPropertyChanging
接口的基类。这个接口意味着它必须跟踪
PropertyChangingEventHandler
处理程序,并在属性即将更改时触发事件。
我们不希望外部类引发该事件,因为那不是它们的职责,让它们这样做只会导致错误。
我们必须让派生类这样做,因为它们可能定义自己的属性,而基类不知道。
因此,在这个基类中定义一个受保护的方法来触发事件。外部类不能调用它(减少了被错误调用的风险),但派生类可以(能够完成它们需要做的工作)。
*来自面向对象背景的人们甚至可能不认为这些数据片段是“对象”。