今天,我读了一本书,作者写道,在一个精心设计的班级中,访问属性的唯一方法是通过其中一种方法。这是一个被广泛接受的想法吗?为什么封装属性如此重要?不这样做会带来什么后果?我早些时候读到,这可以提高安全性或类似的方式。 PHP或Java中的任何例子都会非常有帮助。

有帮助吗?

解决方案

这是一个被广泛接受的想法吗?

在面向对象的世界中,是的。

为什么封装属性如此重要?不这样做会带来什么后果?

对象旨在是包含其他对象可以通过公共接口以受控方式访问的数据和行为的凝聚力实体。如果类不封装其数据和行为,它将不再控制访问的数据,也无法与公共接口所隐含的其他对象履行合同。

这样做的一个大问题之一是,如果必须在内部进行更改,则不必更改公共界面。这样,它不会打破任何代码,其他类也可以像以前一样继续使用。

PHP或Java中的任何例子都会非常有帮助。

这是一个Java示例:

public class MyClass {
    // Should not be < 0
    public int importantValue;
    ...
    public void setImportantValue(int newValue) {
        if (newValue < 0) {
           throw new IllegalArgumentException("value cannot be < 0");
        }
    }
    ...
}

这里的问题是,因为我没有封装 importantValue 通过做 private 任何人都可以出现并绕过我投入的支票,以防止对象具有无效状态。 importantValue 永远不要小于0,但是缺乏封装使得不可能阻止它成为现状。

其他提示

不这样做会带来什么后果?

封装背后的整个想法是,所有与班级有关的知识(除了界面以外)都在类本身中。例如,允许直接访问属性使确保在执行分配的代码上有效任何作业的责任。如果有效变化的定义,您必须通过课程进行审核并确保它们符合所有内容。将规则封装在“设置”方法中意味着您只需要在一个地方更改它,任何尝试任何有趣的呼叫者都可以得到异常,以回报。当属性更改时,您可能还想做很多其他事情,而设置器是这样做的地方。

是否允许直接访问没有任何规则来绑定它们的属性(例如,整数中适合的任何内容都可以)是有争议的。我想,出于一致性的目的,使用Getters和Setter是一个好主意,即,您总是知道可以打电话给 setFoo() 改变 foo 属性而无需查找是否可以直接执行。它们还允许您将未来的班级防守,因此,如果您有其他代码可以执行,那么将其放在那里就已经存在了。

就个人而言,我认为必须使用Getters和Setters看起来很笨拙。我宁愿写 x.foo = 34x.setFoo(34) 并期待某种语言提出相当于成员的数据库触发器的一天,这些触发器允许您定义在作业之前,之后或而不是作业的代码。

关于如何实现“良好的OOD”的观点是一角钱,而且经验丰富的程序员和设计师倾向于在设计选择和哲学上不同意。如果您询问各种各样的语言背景和范式的人,这可能是火焰的起动器。

是的,从理论上讲,理论和实践都是一样的,因此语言选择不应太大影响高级设计。但是在实践中,他们确实如此,因此,好事和坏事发生了。

让我补充一点:这取决于。封装(用支持语言)可以使您对课堂的使用方式有所控制,因此您 能够 告诉人:这是API,您必须使用此方法。在其他语言(例如Python)中毕竟,我们都在这里同意成年人)

封装不是安全功能。

另一个想思考的想法

与登录机的封装还提供了将来更好的可维护性。在上面的Feanor回答中,它可以执行安全检查(假设您的Instvar是私有的)非常有用,但是它可以进一步达到Benifits。

考虑以下情况:
1)您完成应用程序,并将其分发给某些用户(内部,外部,无论如何)。
2)BigCustomera接近您的团队,并希望在产品中添加审核步道。

如果每个人都在其代码中使用访问者方法,那么实现这几乎变得很微不足道。像这样:

Myapi 1.0版

public class MyClass {
    private int importantValue;
    ...
    public void setImportantValue(int newValue) {
        if (newValue < 0) {
           throw new IllegalArgumentException("value cannot be < 0");
        }
        importantValue = newValue;
    }
    ...
}



myapi v1.1(现在有审核步道)

public class MyClass {
    private int importantValue;
    ...
    public void setImportantValue(int newValue) {
        if (newValue < 0) {
           throw new IllegalArgumentException("value cannot be < 0");
        }
        this.addAuditTrail("importantValue", importantValue, newValue);
        importantValue = newValue;
    }
    ...
}

API的现有用户对其代码没有任何更改,现在可以使用新功能(审核跟踪)。
不用封装,以巨大的迁移努力使用您面对的登录器。


第一次编码时,这似乎是很多工作。它的输入速度要快得多: class.varName = something vs class.setVarName(something); 但是,如果每个人都采取简单的出路,那么为BigCustomera的功能请求获得报酬将是一项巨大的努力。

Object Oriente编程 有一个被称为(http://en.wikipedia.org/wiki/open/closed_principle)的原则:poc->> 开放和关闭的原则. 。该原则保留为: 应打开一个井类设计,以供可扩展性(继承),但要修改内部成员(封装). 。这意味着您无法在不关心的情况下修改对象的状态。

因此,新语言仅通过属性(C ++或Java中的Geters和Setters方法)修改内部变量(字段)。在C#属性中编译为MSIL中的方法。

C#:

int _myproperty = 0;
public int MyProperty
{
    get { return _myproperty; }
    set { if (_someVarieble = someConstantValue) { _myproperty = value; } else { _myproperty = _someOtherValue; }  }    
}

C ++/Java:

int _myproperty = 0;
public void setMyProperty(int value) 
{
  if (value = someConstantValue) { _myproperty = value; } else { _myproperty = _someOtherValue; }
}
public int getMyProperty() 
{
    return _myproperty;
}

采取这些想法(来自 首先首先C#):

  • 考虑一下田野可以滥用的方式。如果不正确设置,可能会出问题。
  • 您班上的一切都公开了吗?花一些时间思考封装。
  • 哪些字段需要处理或计算?他们是主要候选人。
  • 如果需要,只有将字段和方法公开。如果您没有理由宣布公开声明,请不要。
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top