代码之家  ›  专栏  ›  技术社区  ›  cvsdave

抽象类中的受保护数据

  •  14
  • cvsdave  · 技术社区  · 16 年前

    我的问题具体涉及Java、抽象类和受保护数据的使用。我被告知所有数据都应该是私有的,并且只使用受保护的getter/setter。

    现在,我知道我们想保护数据不被该类的临时用户直接操纵,而公共数据成员通常是一种可疑的做法。我已经看过“Java保护字段与公共getter”( Java protected fields vs public getters ),但我仍然怀疑:

    protected int i;  
    

    在抽象类中比:

    private int i;  
    protected int geti();  
    protected void seti(int j); 
    

    当抽象类正好为子类提供父类/公共设施,而受保护的范围旨在提供对子类的访问,同时保护数据不被临时用户访问时,我没有看到不利的一面。我在上面提到的问题中注意到,大多数答案似乎都解决了为什么一般数据应该是私有的而不是公共的问题。我试图把我的问题具体地集中在一个抽象的父母中存在的供孩子们使用的数据上。到目前为止,我听到的唯一合理的评论是,使用受父类保护的数据(例如,上面的int I)会在子类中留下引用未在子类中声明的变量的代码。不那么令人信服的是这个论点(参见 Common protected data member in base class? )有一天你可能想改变访问权限,现在你必须尊重你的界面。这是一个抽象类,打算100%地扩展它。

    谢谢具体的标题/页面#参考书籍比参考“.任何基本Java编程文本…”更有帮助

    ========================================== 10-13-2010
    这既是一个关于抽象类的问题,也是一个关于受保护数据的问题。我发现令人失望的是,人们的注意力似乎已经转移到了对数据隐藏在OOP中是否是件好事的回应上(答案:是的)。这里有很多深度涉及抽象类的性质,它与常规非最终类的区别,以及修复抽象父类中供子类使用的数据项的名称和类型可能有哪些优势。我认为创新和更好的控制有可能从抽象的父类扩展到实现的子类。我担心,一般原则,比如数据隐藏的优势,可能会成为教条,阻碍创新和新模式和想法的发展。

    感谢所有做出贡献的人。

    8 回复  |  直到 9 年前
        1
  •  11
  •   alex    16 年前

    如果该字段是私有的,并且通过getter和setter进行访问,那么您将能够重新实现getter和setter(例如,删除该字段并从外部源更新/读取值),从而在不涉及任何子类的情况下更改“字段”的工作方式。

    这是否值得,这取决于你。

        2
  •  9
  •   KeatsPeeks    16 年前

    将受保护的方法视为 界面 对于子类,就像公共方法是其他所有人的接口一样。

    提供访问器使基类能够维护其状态:如果没有故意的欺骗,子类是不可能损坏它的。

        3
  •  3
  •   Skip Head    16 年前

    更少的访问不是缺点,而是好处。类应该总是尽可能多地限制对其内部状态的访问。不要想为什么内部应该隐藏,而是想为什么应该暴露。在这种情况下,就像在所有情况下一样,除非有充分的理由公开变量,否则不要公开它。

        4
  •  1
  •   Colin Hebert    16 年前

    如果你不需要你的孩子 直接地 访问它,你为什么让他们访问?

    使用protected并不是不好的一面。但如果没有必要,也许最好避免它,并控制对字段的访问。

        5
  •  1
  •   Rontologist    16 年前

    在Java中,除了任何扩展类之外,同一个包中的所有成员都可以访问受保护的成员。将字段设置为私有将防止同一包中的类直接访问它。

    还有一点是亚历克斯早些时候提出的。

        6
  •  0
  •   Serplat    16 年前

    如果有人对您的类进行子类化,并将该子类与您当前的类放在同一个包中,他们可能希望覆盖您的getter和setter。例如,他们想确保 i 只能设置为大于1的值。

    除此之外,这真的取决于你。传统的做法是,每件事都有成功者和成功者。

        7
  •  0
  •   Andy Thomas    16 年前

    信息隐藏是有价值的,即使在继承相关的类中也是如此。

    除允许重新实施外,如alex所述:

    • 可以在方法中设置断点。
    • 可以在一个位置添加约束。
        8
  •  0
  •   BlindWanderer    14 年前

    您想要使用getter/setter,因为使用 protected int i; 允许字段重写(无论如何都要避免)。

    您希望禁止字段重写,因为它与方法重写的工作方式不同。字段重写不会使被重写的字段不可访问(引用的类型决定您使用的字段实例)。

    可访问字段应该是final或在final类中。

    public class OverridingFun {
        public static class Base {
            public int i = 1;
            public int getI(){ return i; }
        }
        public static class A extends Base {
            public int i = 2;
            public int getI(){ return i; }
        }
        public static class B extends A {
            public int i = 3;
            public int getI(){ return i; }
        }
        public static void main(String [] args){
            B b = new B();
            A bAsA = b;
            Base bAsBase = b;
    
            System.out.println(b.getI());//3
            System.out.println(bAsA.getI());//3
            System.out.println(bAsBase.getI());//3
    
            System.out.println(b.i);//3
            System.out.println(bAsA.i);//2
            System.out.println(bAsBase.i);//1
    
            b.i = 4;
            bAsA.i = 5;
            bAsBase.i = 6;
    
            System.out.println(b.i);//4
            System.out.println(bAsA.i);//5
            System.out.println(bAsBase.i);//6
        }
    }
    

    乍一看,这看起来只是让代码难以阅读,但它对功能有影响。假设字段确实被派生类覆盖,因为没有使用setter,所以无法自动更新基本字段,也无法检测是否有人更改了基本字段(因为基本值仍然可以访问)并更新派生字段。很容易想象基态和派生态可能会不同步,错误将难以追踪。简单地说,它是一个非常脆弱的API。

    不幸的是,自从第一次世界大战以来,没有办法防止这种情况发生 final 关键字可以防止重写,也可以使字段只写一次。所以没有可写的非重载字段。

    就我个人而言,我很惊讶语言设计者竟然允许字段重写。使用setter的优点是,每个级别都可以保证其自身状态的完整性,并相信派生类没有破坏它。字段重写只是自找麻烦。