定义访问修饰符的意义是什么?

发布于 2024-08-13 21:59:27 字数 332 浏览 8 评论 0原文

我了解它们之间的差异(至少在 C# 中)。我知道它们对分配给它们的元素的影响。我不明白的是为什么实施它们很重要 - 为什么不将所有内容公开?

我读到的关于这个主题的材料通常是关于类和方法如何不应该对其他人进行不必要的访问,但我还没有遇到一个例子来说明为什么/如何这是一件坏事。这看起来像是一个安全问题,但我是程序员;我创建方法并定义它们将(或不会)做什么。为什么我要花费所有的精力来编写一个函数来尝试更改不应该更改的变量,或者尝试读取另一个类中的信息,如果那样会很糟糕?

如果这是一个愚蠢的问题,我深表歉意。这只是我在阅读有关 OOP 的第一篇文章时遇到的东西,但我从来没有觉得它真正引起了我的注意。

I understand the differences between them (at least in C#). I know the effects they have on the elements to which they are assigned. What I don't understand is why it is important to implement them - why not have everything Public?

The material I read on the subject usually goes on about how classes and methods shouldn't have unnecessary access to others, but I've yet to come across an example of why/how that would be a bad thing. It seems like a security thing, but I'm the programmer; I create the methods and define what they will (or will not) do. Why would I spend all the effort to write a function which tried to change a variable it shouldn't, or tried to read information in another class, if that would be bad?

I apologize if this is a dumb question. It's just something I ran into on the first articles I ever read on OOP, and I've never felt like it really clicked.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

女皇必胜 2024-08-20 21:59:27

仅当您是唯一的程序员时,我是程序员才是正确的假设。

在许多情况下,其他程序员会使用第一个程序员的代码。他们以他不希望的方式使用它,通过摆弄他们不应该的字段的值,他们创建了一个可行的黑客,但当原始代码的生产者更改它时就会中断。

OOP 是关于创建具有明确定义的契约的库。如果所有变量都是公共的并且可供其他人访问,那么“契约”理论上包括对象(及其子对象)中的每个字段,因此构建仍然遵循原始契约的新的、不同的实现变得更加困难。

此外,对象暴露的“移动部分”越多,类的用户就越容易错误地操作它。


您可能不需要这个,但这里有一个我认为很有趣的例子:

假设您出售一辆发动机舱上没有引擎盖的汽车。到了晚上,司机打开车灯。他到达目的地,下了车,然后想起他把灯开着。他懒得打开车门,所以他把车灯的电线从与电池相连的地方拉出来。这很好用——灯灭了。然而,由于他没有使用预期的机制,下次在黑暗中开车时他发现自己遇到了问题。

生活在美国(来吧,给我投反对票!),他拒绝为他对汽车内部结构的错误使用承担责任,并起诉你,制造商,因为你创造了一种在黑暗中驾驶不安全的产品,因为灯不能关断后能可靠地开启。

这就是为什么所有汽车的发动机舱上都有引擎盖 :)


一个更严重的例子:您创建一个 Fraction 类,其中包含分子和分母字段以及一系列操作分数的方法。您的构造函数不允许其调用者创建分母为 0 的分数,但由于您的字段是公共的,因此用户很容易将现有(有效)分数的分母设置为 0,并且随之而来的是欢闹。

I'm the programmer is a correct assumption only if you're the only programmer.

In many cases, other programmers work with the first programmer's code. They use it in ways he didn't intend by fiddling with the values of fields they shouldn't, and they create a hack that works, but breaks when the producer of the original code changes it.

OOP is about creating libraries with well-defined contracts. If all your variables are public and accessible to others, then the "contract" theoretically includes every field in the object (and its sub-objects), so it becomes much harder to build a new, different implementation that still honors the original contract.

Also, the more "moving parts" of your object are exposed, the easier it is for a user of your class to manipulate it incorrectly.


You probably don't need this, but here's an example I consider amusing:

Say you sell a car with no hood over the engine compartment. Come nighttime, the driver turns on the lights. He gets to his destination, gets out of the car and then remembers he left the light on. He's too lazy to unlock the car's door, so he pulls the wire to the lights out from where it's attached to the battery. This works fine - the light is out. However, because he didn't use the intended mechanism, he finds himself with a problem next time he's driving in the dark.

Living in the USA (go ahead, downvote me!), he refuses to take responsibility for his incorrect use of the car's innards, and sues you, the manufacturer for creating a product that's unsafe to drive in the dark because the lights can't be reliably turned on after having been turned off.

This is why all cars have hoods over their engine compartments :)


A more serious example: You create a Fraction class, with a numerator and denominator field and a bunch of methods to manipulate fractions. Your constructor doesn't let its caller create a fraction with a 0 denominator, but since your fields are public, it's easy for a user to set the denominator of an existing (valid) fraction to 0, and hilarity ensues.

戏蝶舞 2024-08-20 21:59:27

首先,语言中没有任何内容强制您使用访问修饰符 - 如果您愿意,您可以自由地将所有内容公开在您的类中。然而,使用它们有一些令人信服的理由。这是我的观点。

  1. 隐藏类的内部运作方式可以让您保护该类免遭意外使用。虽然您可能是该类的创建者,但在许多情况下您不会是唯一的消费者 - 或者甚至维护者。隐藏内部状态可以为那些可能不像您一样理解其工作原理的人保护该类。当类没有按照您希望的方式运行时,将所有内容公开会产生“调整”内部状态或内部行为的诱惑,而不是实际纠正内部实现的公共接口。这是通往毁灭之路。

  2. 隐藏内部结构有助于整理命名空间,并允许 Intellisense 等工具仅显示相关且有意义的方法/属性/字段。不要低估像 Intellisense 这样的工具 - 它们是开发人员快速识别他们可以对您的类执行哪些操作的强大手段。

  3. 隐藏内部结构允许您构建适合该类正在解决的问题的接口。暴露所有内部结构(通常远远超过暴露的接口)使得以后很难理解该类试图解决什么问题。

  4. 隐藏内部结构使您可以将测试集中在适当的部分 - 公共接口。当类的所有方法/属性都是公共的时,您必须潜在测试的排列数量显着增加 - 因为任何特定的调用路径都成为可能。

  5. 隐藏内部结构可帮助您控制(强制)类中的调用路径。这可以更轻松地确保您的消费者了解可以要求您的类执行什么操作以及何时执行。通常,代码中只有少数路径是有意义且有用的。允许消费者采取任何路径会使他们更有可能得不到有意义的结果 - 并将其解释为您的代码有错误。限制消费者使用您的类的方式实际上可以让他们正确使用它。

  6. 隐藏内部实现可以让您自由地更改它,并且知道它不会对您的类的使用者产生不利影响 - 只要您的公共接口保持不变。如果您决定在内部使用字典而不是列表 - 没有人会关心。但是,如果您使类的所有内部结构都可用,那么有人可以编写取决于您内部使用列表这一事实的代码。想象一下,当您想要更改有关实现的此类选择时,必须更改所有消费者。黄金法则是:类的使用者不应该关心该类如何执行其功能。

First, nothing in the language forces you to use access modifiers - you are free to make everything public in your class if you wish. However, there are some compelling reasons for using them. Here's my perspective.

  1. Hiding the internals of how your class operates allows you to protect that class from unintended uses. While you may be the creator of the class, in many cases you will not be the only consumer - or even maintainer. Hiding internal state protects the class for people who may not understand its workings as well as you. Making everything public creates the temptation to "tweak" the internal state or internal behavior when the class isn't acting the way you may want - rather than actually correcting the public interface of internal implementation. This is the road to ruin.

  2. Hiding internals helps to de-clutter the namespace, and allows tools like Intellisense to display only the relevant and meaningful methods/properties/fields. Don't discount tools like Intellisense - they are a powerful means for developers to quickly identify what they can do with your class.

  3. Hiding internals allows you to structure an interface appropriate for the problem the class is solving. Exposing all of the internals (which often substantially outnumber the exposed interface) makes it hard to later understand what the class is trying to solve.

  4. Hiding internals allows you to focus your testing on the appropriate portion - the public interface. When all methods/properties of a class are public, the number of permutations you must potentially test increases significantly - since any particular call path becomes possible.

  5. Hiding internals helps you control (enforce) the call paths through your class. This makes it easier to ensure that your consumers understand what your class can be asked to do - and when. Typically, there are only a few paths through your code that are meaningful and useful. Allowing a consumer to take any path makes it more likely that they will not get meaningful results - and will interpret that as your code being buggy. Limiting how your consumers can use your class actually frees them to use it correctly.

  6. Hiding the internal implementation frees you to change it with the knowledge that it will not adversely impact consumers of your class - so long as your public interface remains unchanged. If you decide to use a dictionary rather than a list internally - no one should care. But if you made all the internals of your class available, someone could write code that depends on the fact that your internally use a list. Imagine having to change all of the consumers when you want to change such choices about your implementation. The golden rule is: consumers of a class should not care how the class does what it does.

神也荒唐 2024-08-20 21:59:27

它主要是一种隐藏和共享的东西。您可以生成并使用自己的所有代码,但其他人提供库等以更广泛地使用。

将事物设为非公开允许您显式定义类的外部接口。非公共内容不是外部接口的一部分,这意味着您可以在内部更改任何您想要的内容,而不会影响任何使用外部接口的人,

It is primarily a hiding and sharing thing. You may produce and use all your own code, but other people provide libraries, etc. to be used more widely.

Making things non-public allows you to explicitly define the external interface of your class. The non-public stuff is not part of the external interface, which means you can change anything you want internally without affecting anyone using the external interface,

寄居人 2024-08-20 21:59:27

您只想公开 API 并隐藏其他所有内容。为什么?
好吧,假设您想要创建一个很棒的 Matrix 库,因此您

class Matrix {
   public Object[][] data //data your matrix storages
   ...
   public Object[] getRow()
}

默认使用您的库的任何其他程序员都希望通过利用底层结构来最大化其程序的速度。

//Someone else's function
Object one() {data[0][0]}

现在,您发现使用列表来模拟矩阵会提高性能,因此您更改数据不会

Object[][] data => Object[] data

导致 Object one() 中断。换句话说,通过更改实现,您破坏了向后兼容性:-(

通过封装,您将内部实现与外部接口分开(通过 private 修饰符实现)。
这样你就可以在不破坏向后兼容性的情况下尽可能地改变实现:D利润!!!

当然,如果您是唯一要修改或使用该类的程序员,您最好将其公开。

注意:封装你的东西还有其他主要好处,这只是其中之一。有关更多详细信息,请参阅封装

You only want to expose the API and keep everything else hidden. Why?
Ok lets assume you want to make an awesome Matrix library so you make

class Matrix {
   public Object[][] data //data your matrix storages
   ...
   public Object[] getRow()
}

By default any other programmer that use your library will want to maximize the speed of his program by tapping into the underlying structure.

//Someone else's function
Object one() {data[0][0]}

Now, you discover that using list to emulate the matrix will increase performance so you change data from

Object[][] data => Object[] data

causes Object one() to break. In other words by changing your implementation you broke backward compatibility :-(

By encapsulating you divide internal implementation from external interface (achieved with a private modifier).
That way you can change implementation as much as possible without breaking backward compatibility :D Profit!!!

Of course if you are the only programmer that is ever going to modify or use that class you might as well as keep it public.

Note: There are other major benefits for encapsulating your stuff, this is just one of many. See Encapsulation for more details

如此安好 2024-08-20 21:59:27

我认为最好的原因是在代码上提供抽象层。

随着应用程序的增长,您将需要让您的对象与其他对象进行交互。拥有可公开修改的字段会让您更难理解整个应用程序。

限制在类上公开的内容可以更轻松地抽象设计,以便您可以理解代码的每一层。

I think the best reason for this is to provide layers of abstraction on your code.

As your application grows, you will need to have your objects interacting with other objects. Having publicly modifiable fields makes it harder to wrap your head around your entire application.

Limiting what you make public on your classes makes it easier to abstract your design so you can understand each layer of your code.

故人如初 2024-08-20 21:59:27

对于某些类,拥有私有成员以及一堆仅设置和获取这些值的方法似乎很荒谬。其原因是,假设您有一个类,其中的成员是公共的并且可以直接访问:

class A 
{
    public int i;

   ....
}

现在您继续在编写的一堆代码中使用它。现在,在编写了一堆直接访问 i 的代码之后,您意识到 i 应该对其有一些限制,例如 i 应该始终 >= 0 且小于 100(为了论证)。
现在,您可以检查使用 i 的所有代码并检查此约束,但您可以只添加一个公共 setI 方法来为您完成此操作:

class A
{
    private int i;
    public int I 
    {
        get {return i;}
        set 
        {
            if (value >= 0 && value < 100)
                i = value;
            else
                throw some exception...
         }
    }
}

这隐藏了所有错误检查。虽然这个例子很老套,但类似的情况经常出现。

For some classes, it may seem ridiculous to have private members, with a bunch of methods that just set and get those values. The reason for it is that let's say you have a class where the members are public and directly accessible:

class A 
{
    public int i;

   ....
}

And now you go on using that in a bunch of code you wrote. Now after writing a bunch of code that directly accesses i and now you realize that i should have some constraints on it, like i should always be >= 0 and less than 100 (for argument's sake).
Now, you could go through all of your code where you used i and check for this constraint, but you could just add a public setI method that would do it for you:

class A
{
    private int i;
    public int I 
    {
        get {return i;}
        set 
        {
            if (value >= 0 && value < 100)
                i = value;
            else
                throw some exception...
         }
    }
}

This hides all of that error checking. While the example is trite, situations like these come up quite often.

扛起拖把扫天下 2024-08-20 21:59:27

它与安全完全无关。

访问修饰符和范围都与结构、层、组织和通信有关。

如果你是唯一的程序员,那么可能没什么问题,除非你有这么多代码,甚至你都记不清了。那时,它就像一个团队环境 - 访问修饰符和代码结构引导您留在架构内。

It is not related to security at all.

Access modifers and scope are all about structure, layers, organization, and communication.

If you are the only programmer, it is probably fine until you have so much code even you can't remember. At that point, it's just like a team environment - the access modifiers and the structure of the code guide you to stay within the architecture.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文