为什么受保护的成员变量被视为反模式,应该用私有访问字段替换?

时间:2016-02-04 19:57:26

标签: java inheritance design-patterns

我最近获得了建议,将基类中所有受保护的成员变量更改为私有访问。

但实际使用方面的唯一优势是能够对它们进行单独的读取,写入和读取/写入访问,以防止滥用。以下Java代码详细介绍了这种用法。

public class BaseClass {
    protected Object protectedMember;

    private Object privateMemberR;
    private Object privateMemberW;
    private Object privateMemberRW;

    public BaseClass() {

    } 

    protected final Object getPrivateMemberR(Object obj){
        return privateMemberR;
    }

    protected final void setPrivateMemberW(Object obj){
        privateMemberW = obj;
    }

    protected final Object getPrivateMemberRW(Object obj){
        return privateMemberRW;
    }

    protected final void setPrivateMemberRW(Object obj){
         privateMemberRW = obj;
    }
}

也许并不总是需要宣布他们是最终的,只是为了确保他们不被覆盖和滥用。

我读了类似Clean code questions这样的论点,但是如果我可以使用私有成员变量,我会首先将它们设为私有。

此外,至少在Java中,您只能使用覆盖方法的访问修饰符来允许比超类方法更多但不是更少的访问,您仍然要拖动受保护的成员变量或受保护的getter和setter all你的子类中的方式。

我没有考虑多重继承,因为Java不允许它,但我仍然没有看到如何使用标准符号表示getter和setter,你可以避免遇到问题。

在实际使用方面是否有任何其他实际好处(除了它看起来更漂亮和更容易阅读,神奇地希望你通过用吸气剂和制定者替换直接参考来防止不当使用)

2 个答案:

答案 0 :(得分:1)

它实际上取决于上下文。根据您的设计,这更像是一个偏好问题。

例如,您知道private和protected之间的唯一区别是子类和包访问。

            | Class | Package | Subclass | World
————————————+———————+—————————+——————————+———————
protected   |  y    |    y    |    y     |   n
————————————+———————+—————————+——————————+———————
private     |  y    |    n    |    n     |   n

它似乎也更容易编码"因为子类可以直接访问受保护的字段,而不是使用方法来访问超类中的私有字段,但这可能会破坏目的......

你必须检查你的继承,并确保在使用受保护时不要让任何漏洞。例如,直接访问您的子类?

私人:有人可能无法按照您的实施做他们想做的事。

其他人:有些人可能会做一些你真的不希望他们与你的实施有关的事情。

Reasons to use private instead of protected for fields and methods

在我看来,你需要有一个特殊的理由来制作比私人更容易获得的东西......

答案 1 :(得分:1)

这完全取决于。在不知道子类能够访问某个字段的具体原因的情况下,很难说明适当的保护级别。

决定的一个重要因素是该类是否用于进行子类化;如果它没有明确地设计为可扩展的,那么保持其内部工作是私有的是一个合理的默认选择。

当要将类设置为子类时,它会变得毛茸茸子类需要对基类进行一些控制。

如果子类显然需要同时读取和写入字段,那么私有字段的所有受保护的getter / setter都可以为您购买,是:

a。)在发生不正确使用(例如通过投掷)的情况下验证和回应的可能性,而不是更晚。这可以通过避免在某一点上某个字段被不正确地更改的情况来节省大量时间,从而导致以后在不相关的地方出现很多的问题。

b。)灵活地改变字段表示而无需更改现有的子类。我认为这是一个非常罕见的案例;如果字段类型可以更改并且子类与基类紧密相关,那么您不太可能只是在getter / setter中转换表示。

c。)如果子类只需要读取一个字段,那么显而易见 只是提供一个getter防御子类改变那个字段。没有可用的setter明确表示该成员不打算被更改。如果可能,使 final 字段可以替代提供受保护的getter。

可能有另一种选择:打包私人访问

这是一个经常被忽视的选择。在许多情况下,您需要一个提供最通用实现的基类,然后是 user 可以扩展的两个或多个变体。变体需要访问基类成员,但用户派生的子类不应该。然后,包私有只是工作的工具。