Java:面向对象封装 VS 未封装?

3

你好,我为我的Java课程编写了一个二叉树程序,但因为“没有面向对象封装”而扣了很多分。但我认为封装只是使用类,这样不就可以了吗?为了实现面向对象封装,我应该做些什么不同的事情呢?以下是我的工作代码。感谢任何意见或建议。

public class BinTree {


    private Node root;


    private static class Node{
            Node left;
            Node right;
            int value;


            Node(int newValue){
                    left = null;
                    right = null;
                    value = newValue;
            }


    }


    BinTree(){
            root = null;
    }


    public void insertNode(int value){
            root = insertNode(root, value);
    }


    private Node insertNode(Node node, int value){


            if (node==null){
                    node = new Node(value);
            }
            else{
                    if (value <= node.value){
                            node.left = insertNode(node.left, value);
                    }
                    else {
                            node.right = insertNode(node.right, value);
                    }
            }
            return(node);
    }


    public void treeWalk(){


            treeWalk(root);
    }


    private void treeWalk(Node node){


            if(node != null){


                    treeWalk(node.left);
                    System.out.println(node.value);
                    treeWalk(node.right);
            }


    }
}

这个类以外访问了哪些方法? - BitNinja
@codeNinja - 只有可见的...显然。 - Stephen C
4个回答

5

@Marco13可能是正确的,但要确定标记者的意思,实际上需要询问他或她。


就我所知,我认为您的标记是错误的。显然,外部类被正确地封装,嵌套类是私有的,这意味着它在外部类的封装边界之外不可见。

Java的惯例是,私有内部类不一定需要为其字段设置getter和setter。

封装不是一种信仰。它在Java中用于某个目的,即防止实现细节泄漏。声明getter和setter也有助于子类化。但是,当所谓的目的无关紧要时(如此处),使用封装是不必要的。

如果您想要一个恰当的示例,请查看标准LinkedList类的Java源代码:

请注意,Entry类没有getter或setter...它的字段也没有声明为final。


+1 为这个进行详细阐述。虽然我认为在这种情况下使用甚至是 私有 的 setter/getter 也不会有害,但有些人似乎过于盲目地遵循“封装 == 使用getter和setter”的过度简化原则,而忽略了实际要点。 - Marco13
同意。在这种情况下使用getter/setter并不会有害。但也不是必需的。 - Stephen C

3
当这是一个任务时,“无OOP封装”这个术语可能指的是您没有为Node类的字段使用setter和getter。因此,您应该将left、right和value设置为private,并相应地提供用于读取/写入这些字段值的方法。
(请注意,在这种情况下,“封装”也意味着您不必创建修改value的方法:这仅在构造函数中设置,以后不能更改。因此,实际上,value甚至可以(并且应该)是private final。)

2

维基百科写道

根据这个定义,封装意味着对象的内部表示通常对于对象定义之外的视图是隐藏的。通常,只有对象自己的方法可以直接检查或操作它的字段。

在您的情况下,Node类的字段是从BinTree类的方法中访问的。因此,Node并没有对BinTree进行封装。

您的老师可能希望您将访问节点状态的方法移动到节点类中:

class BinTree {

    private Node root;

    private static class Node {
        Node left;
        Node right;
        int value;

        Node(int newValue) {
            left = null;
            right = null;
            value = newValue;
        }

        void insert(int newValue) {
            if (newValue <= value) {
                if (left == null) {
                    left = new Node(newValue);
                } else {
                    left.insert(newValue);
                }
            } else {
                if (right == null) {
                    right = new Node(newValue);
                } else {
                    right.insert(newValue);
                }
            }
        }

        void walk() {
            if (left != null) {
                left.walk();
            }
            System.out.println(value);
            if (right != null) {
                right.walk();
            }
        }

    }

    BinTree() {
        root = null;
    }

    public void insertNode(int value) {
        if (root == null) {
            root = new Node(value);
        } else {
            root.insert(value);
        }
    }

    public void treeWalk() {
        if (root != null) {
            root.walk();
        }
    }
}

现在,这是否是更好的设计还有些值得怀疑。当然,面向对象纯粹主义者会为更短的参数列表和所有方法只访问this字段而欢呼,但实用主义程序员会发现重复的空检查与您的方法缺乏严格封装一样糟糕,甚至更糟。
个人认为,封装(或更普遍的信息隐藏)是编写除最简单程序以外所有程序都必不可少的技术。但我不同意一个胶囊的适当大小总是一个单一的对象。在您原始的代码中,胶囊包围整个树,对我来说已经足够好了。

0
面向对象编程(OOP)的思想是使代码更具可重用性和更像对象,当你创建一个对象时,你希望能够使用该对象的所有函数,这也包括访问数据。问题在于创建多个类型的对象并意外覆盖数据的值。这就是为什么需要封装。
以下是封装的示例:
private int health;

public void getHealth(){
 return health;
}

public int setHealth(int h){
 this.health = h;
}

你问为什么要为这个属性设置两种方法?当你实例化这个类时,你不想直接访问它的属性,而是间接地访问以避免覆盖其默认值。你将属性设置为私有,这样任何类都不能直接调用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接