封装 - 当设置者已经公开时我们为什么需要它?

Dan*_*elo 30 .net c++ java oop encapsulation

封装是隐藏数据.我想在这里听到一些非常有趣的答案.

private当我们已经public为变量声明setter方法时,保持变量的背后有什么意义?

我理解封装的用法,但是当我们将setter作为public时,保持变量的背后是什么private,我们可以直接使用public访问修饰符

是因为我们不希望其他人知道我们在后端存储数据或管理数据的确切方式吗?

Kon*_*man 32

是因为我们不希望其他人知道我们在后端存储数据或管理数据的确切方式吗?

是的,这就是重点.它也与抽象信息隐藏的概念有关.

您提供了一个公共setter,当由类客户端调用时,它将具有您已记录的效果.客户的业务如何实现这种效果并非如此.你在修改其中一个类属性吗?好吧,让客户知道,但不是你实际修改变量的事实.在将来,您可能希望修改您的类,以便它使用完全不同的东西(属性字典?外部服务?随便!)而不是简单的备份变量,而客户端不会破坏.

所以你的setter是一个抽象,你提供给客户端"修改这个类属性".与此同时,您隐藏了使用内部变量的事实,因为客户端不需要知道这一事实.

(注意:这里我使用"属性"这个词作为通用概念,与任何具体的编程语言无关)

  • 抽象是关于隐藏_implementation_而不是功能. (6认同)

Com*_*sMS 23

我完全同意Konamiman的回答,但我想补充一点:

有些情况下你真的不想要这种抽象.那没关系.

我想在这里使用的一个简单示例是一个三维浮点向量的类:

class Vector3f {
public:
    float x;
    float y;
    float z;
};
Run Code Online (Sandbox Code Playgroud)

你可以将这些字段设为私有并提供安装者吗?当然,你可以.但是在这里你可能会争辩说这个类实际上只是提供了一个浮点元组,你不需要任何额外的功能.因此,添加setter只会使类复杂化,而您宁愿将字段保留为public.

现在,您可以轻松构建可能会在以后咬你的场景.例如,您可能有一天会得到一个要求,即Vector3f不允许存储NaNs并且如果有人试图这样做,则应该抛出异常.但是这样一个假设的未来问题不足以证明引入额外的抽象是合理的.

这是您的通话作为一个程序员决定哪些抽象的手做出这个问题的意义,哪些只会在你完成工作的方式获得.不必要的抽象是过度工程化的,会影响你的工作效率,就像不抽象一样.

一句话:不要因为有人声称这是一个好习惯而盲目地使用setter.相反,考虑手头的问题并考虑权衡.

  • 好的,就是我说的,取决于你实际需要什么. (2认同)

Jaw*_*wad 11

因为通过封装,我们提供单点访问.假设您按如下方式定义变量及其setter

String username; 

public void setUsername(String username){
this.username = username;
}
Run Code Online (Sandbox Code Playgroud)

稍后您想在设置username属性之前添加一些验证.如果您通过直接访问该属性将用户名设置为10个位置,那么您没有单点访问权限,您需要在10个位置进行此更改.但是,如果您有一个setter方法,那么通过在一个地方进行更改,您可以轻松实现结果.


InB*_*een 5

尽管Konamiman答案很明显,但我想补充一点,在公共场所的特定情况下,与直接暴露你所要求的公共领域相比,除了信息隐藏解耦实现之外,还有另一个非常重要的区别.来自公共表面或API的类; 验证.

在公共字段方案中,无法在修改字段时验证字段的值.如果是公共setter(可以是Foo {get; set;}属性或a SetFoo(Foo value))方法,您可以添加验证代码并启动所需的副作用,这样可以确保您的类始终处于有效或可预测的状态.


zul*_*hah 5

想一想:我通过一个类来代表一个现实生活中的对象,一只狮子。我会做这样的事情。

class Lion {
    public int legs;
}
Run Code Online (Sandbox Code Playgroud)

现在其他一些开发人员需要我的类来创建一个对象并设置它的腿字段。他会做这样的事情

Lion jungleKing = new Lion();
jungleKing.legs = 15;
Run Code Online (Sandbox Code Playgroud)

现在的问题是,Java 不会限制他将任何超过 4 的数字设置为该对象的腿数。这不是错误,它会运行得很好。但这是一个逻辑错误,编译器不会帮助你。这样狮子可能有任意数量的腿。但是如果我们这样写代码

class Lion {
    private int legs;
    public void setLegs(int legs){
        if(legs > 4){
            this.legs = 4;
         }
        else this.legs = legs;
    } 
}
Run Code Online (Sandbox Code Playgroud)

现在你不会有任何超过 4 条腿的 Lion,因为更新类字段的策略已由类本身定义,并且没有任何人不知道该策略会更新腿字段,因为这是唯一的方法更新腿字段是通过 setLegs() 方法,该方法知道类的策略。