需要封装不良的示例

时间:2018-12-17 19:08:41

标签: java

我想看到一个示例,该示例直接从使用公开声明的数据成员的类中获取代码,以查看封装不良的示例,因此,通过与不良示例进行对比,我可以理解OOP中封装的良好示例。(被告知要使用封装而没有不好的例子,就像被告知不要在不了解偷窃对我来说是偷窃一样。)谢谢。

2 个答案:

答案 0 :(得分:2)

假设您有一个Counter类,

  1. 从值= 0开始
  2. 让您将值增加一(increment
  3. 让您看到当前值

封装不好的版本将直接公开内部计数器值:

class Counter {
    public int value;

    public Counter() {
        this.value = 0;
    }

    public int increment() {
        return ++this.value;
    }
}

当然,问题在于该类的用户可以做到这一点:

Counter c = new Counter();
System.out.println(c.value); // 0
c.increment();
System.out.println(c.value); // 1
c.value = 42;
System.out.println(c.value); // 42

正确的封装可以纠正以下问题:

class Counter {
    private int value;         // *** Private

    public Counter() {
        this.value = 0;
    }

    public int increment() {
        return ++this.value;
    }

    public int getValue() {    // *** Accessor
        return this.value;
    }
}

现在,班级用户无法直接设置value

Counter c = new Counter();
System.out.println(c.getValue()); // 0
c.increment();
System.out.println(c.getValue()); // 1
// No equivalent to `c.value = 42` is possible here¹

¹(不使用反射)

答案 1 :(得分:0)

您的问题是一个有用的问题,因为了解封装很重要的原因将帮助您避免过于概括性地讲解原理,并帮助您充分理解封装原理。

您可以在此处找到封装效果不佳的示例:https://github.com/dotnet/training-tutorials/blob/master/content/csharp/getting-started/encapsulation-oop.md当示例中的类被其他代码用于执行常规操作时,由于未封装该类,因此会产生问题。 (其他示例可能会说明由 poor 封装而不是 lack 封装引起的问题,但我知道您需要一个基本概念的示例。)

很多时候,由于没有封装代码而导致的问题是,当属性和/或对象是您实际希望更新或删除的对象的副本时,属性和/或对象将被更新或删除。

这是链接示例的一些相关部分。第一个引号描述了该类缺少封装时所产生的问题:

  

请注意,在此示例中,用于打印订单的技术是while循环,该循环会在打印每条记录时将其丢弃。这是一个实现细节,如果正确处理了此循环使用的集合,则不会造成任何问题。不幸的是,即使使用本地范围内的订单变量来表示集合,对RemoveAt的调用实际上仍在从基础Customer对象中删除记录。在计划结束时,两个客户都有0个订单。这不是预期的行为。

第二个引号中指出,可以通过不同的实现方式“解决”该问题,但可以完全避免使用封装:

  

有多种方法可以解决此问题,最简单的方法是将while循环更改为foreach,但是潜在的问题是Customer不能以任何方式封装其Orders属性。即使不允许其他类设置该属性,它公开的List类型也会破坏封装,并允许协作者任意删除甚至清除集合的内容。

此示例很好地说明了封装的需求不是绝对的,但肯定是最佳实践。

相关问题