You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
One of the most important principles of object oriented programming -- delimiting internal interface from the external one.
4
+
面向对象编程最重要的原则之一 —— 划分出外部接口和内部接口。
5
5
6
-
That is "a must" practice in developing anything more complex than a "hello world" app.
6
+
在开发比 “hello world” 应用更复杂的东西时,这是“必须”的做法。
7
7
8
-
To understand this, let's break away from development and turn our eyes into the real world.
8
+
为了理解这一点,让我们脱离开发过程,把目光转向现实世界。
9
9
10
-
Usually, devices that we're using are quite complex. But delimiting the internal interface from the external one allows to use them without problems.
10
+
通常,我们使用的设备非常复杂。但是划分出外部接口和内部接口可以让我们使用它们而没有任何问题。
11
11
12
-
## A real-life example
12
+
## 一个真实的例子
13
13
14
-
For instance, a coffee machine. Simple from outside: a button, a display, a few holes...And, surely, the result -- great coffee! :)
14
+
例如咖啡机。从外面看很简单:一个按钮,一个显示器,几个洞……当然,结果就是 —— 很棒的咖啡!:)
15
15
16
16

17
17
18
-
But inside... (a picture from the repair manual)
18
+
但在里面……(维修手册中的图片)
19
19
20
20

21
21
22
-
A lot of details. But we can use it without knowing anything.
22
+
有很多细节。但我们可以在不了解的情况下使用它。
23
23
24
-
Coffee machines are quite reliable, aren't they? We can use one for years, and only if something goes wrong -- bring it for repairs.
24
+
咖啡机非常可靠,不是吗?我们可以使用好几年,只有在出现问题时 —— 进行维修。
25
25
26
-
The secret of reliability and simplicity of a coffee machine -- all details are well-tuned and *hidden* inside.
26
+
咖啡机的可靠性和简洁性的秘诀 —— 所有细节都经过精心调整并 **隐藏** 在内部。
27
27
28
-
If we remove the protective cover from the coffee machine, then using it will be much more complex (where to press?), and dangerous (it can electrocute).
28
+
如果我们从咖啡机上取下保护盖,那么使用它将会复杂得多(要按哪里?),并且危险(会触电)。
29
29
30
-
As we'll see, in programming objects are like coffee machines.
30
+
正如我们所看到的,在编程中,对象就像咖啡机。
31
31
32
-
But in order to hide inner details, we'll use not a protective cover, but rather special syntax of the language and conventions.
32
+
但是为了隐藏内部细节,我们不会使用保护盖,而是使用语言和惯例中的特殊语法。
33
33
34
-
## Internal and external interface
34
+
## 内部接口和外部接口
35
35
36
-
In object-oriented programming, properties and methods are split into two groups:
36
+
在面向对象的编程中,属性和方法分为两组:
37
37
38
-
-*Internal interface* -- methods and properties, accessible from other methods of the class, but not from the outside.
39
-
-*External interface* -- methods and properties, accessible also from outside the class.
38
+
-**内部接口** —— 可以通过类的其他方法访问,但不能从外部访问的方法和属性。
39
+
-**外部接口** —— 也可从类的外部访问的方法和属性。
40
40
41
-
If we continue the analogy with the coffee machine -- what's hidden inside: a boiler tube, heating element, and so on -- is its internal interface.
41
+
如果我们继续用咖啡机进行类比 —— 内部隐藏的内容:锅炉管,加热元件等 —— 是其内部的接口。
42
42
43
-
An internal interface is used for the object to work, its details use each other. For instance, a boiler tube is attached to the heating element.
43
+
内部接口用于对象,它的细节相互使用。例如,锅炉管连接到加热元件。
44
44
45
-
But from the outside a coffee machine is closed by the protective cover, so that no one can reach those. Details are hidden and inaccessible. We can use its features via the external interface.
So, all we need to use an object is to know its external interface. We may be completely unaware how it works inside, and that's great.
47
+
所以,我们需要使用一个对象时只需知道它的外部接口。我们可能完全不知道它的内部是如何工作的,这很棒。
48
48
49
-
That was a general introduction.
49
+
这是个概括的介绍。
50
50
51
-
In JavaScript, there are three types of properties and members:
51
+
在 JavaScript 中,有两种类型的对象字段(属性和方法):
52
52
53
-
-Public: accessible from anywhere. They comprise the external interface. Till now we were only using public properties and methods.
54
-
-Private: accessible only from inside the class. These are for the internal interface.
53
+
-公共的:可从任何地方访问。它们包含外部接口。直到现在我们只使用公共属性和方法。
54
+
-私有的:只能从类的内部访问。这些用于内部接口。
55
55
56
-
In many other languages there also exist "protected" fields: accessible only from inside the class and those extending it. They are also useful for the internal interface. They are in a sense more widespread than private ones, because we usually want inheriting classes to gain access to properly do the extension.
In the next step we'll make a coffee machine in JavaScript with all these types of properties. A coffee machine has a lot of details, we won't model them to stay simple (though we could).
**Protected properties are usually prefixed with an underscore `_`.**
88
+
**受保护的属性通常以下划线 `_` 作为前缀。**
89
89
90
-
That is not enforced on the language level, but there's a convention that such properties and methods should not be accessed from the outside. Most programmers follow it.
90
+
这不是在语言层面强制实施的,但是有一个在程序员之间人尽皆知的惯例是不应该从外部访问这些属性和方法。
91
91
92
-
So our property will be called `_waterAmount`:
92
+
所以我们的属性将被称为 `_waterAmount` :
93
93
94
94
```js run
95
95
classCoffeeMachine {
@@ -110,22 +110,22 @@ class CoffeeMachine {
110
110
111
111
}
112
112
113
-
//create the coffee machine
113
+
//创建咖啡机
114
114
let coffeeMachine =newCoffeeMachine(100);
115
115
116
-
//add water
116
+
//加入水
117
117
coffeeMachine.waterAmount=-10; // Error: Negative water
118
118
```
119
119
120
-
Now the access is under control, so setting the water below zero fails.
120
+
现在访问受到控制,因此将水量设置为小于零的数将会失败。
121
121
122
-
## Read-only "power"
122
+
## 只读的“power”
123
123
124
-
For`power`property, let's make it read-only. It sometimes happens that a property must be set at creation time only, and then never modified.
124
+
对于`power`属性,让我们将它设为只读的。有时候一个属性必须仅在创建时设置,然后不再修改。
125
125
126
-
That's exactly the case for a coffee machine: power never changes.
126
+
这就是咖啡机的实际情况:功率永远不会改变。
127
127
128
-
To do so, we only need to make getter, but not the setter:
128
+
要做到这一点,我们只需要设置 getter,而不是 setter:
129
129
130
130
```js run
131
131
classCoffeeMachine {
@@ -141,18 +141,18 @@ class CoffeeMachine {
141
141
142
142
}
143
143
144
-
//create the coffee machine
144
+
//创建咖啡机
145
145
let coffeeMachine =newCoffeeMachine(100);
146
146
147
-
alert(`Power is: ${coffeeMachine.power}W`); //Power is: 100W
147
+
alert(`Power is: ${coffeeMachine.power}W`); //功率是:100W
148
148
149
149
coffeeMachine.power=25; // Error (no setter)
150
150
```
151
151
152
-
````smart header="Getter/setter functions"
153
-
Here we used getter/setter syntax.
152
+
````smart header="Getter/setter 函数"
153
+
这里我们使用 getter/setter 语法。
154
154
155
-
But most of the time `get.../set...` functions are preferred, like this:
155
+
但大多数时候首选 `get.../set...` 函数,像这样:
156
156
157
157
```js
158
158
class CoffeeMachine {
@@ -171,28 +171,28 @@ class CoffeeMachine {
171
171
new CoffeeMachine().setWaterAmount(100);
172
172
```
173
173
174
-
That looks a bit longer, but functions are more flexible. They can accept multiple arguments (even if we don't need them right now). So, for the future, just in case we need to refactor something, functions are a safer choice.
174
+
这看起来有点长,但函数更灵活。他们可以接受多个参数(即使我们现在不需要它们)。
175
175
176
-
Surely, there's a tradeoff. On the other hand, get/set syntax is shorter, so ultimately there's no strict rule, it's up to you to decide.
176
+
另一方面,get/set 语法更短,所以最终没有严格的规则,而是由你自己来决定。
177
177
````
178
178
179
-
```smart header="Protected fields are inherited"
180
-
If we inherit `class MegaMachine extends CoffeeMachine`, then nothing prevents us from accessing `this._waterAmount` or `this._power` from the methods of the new class.
In many scenarios such limitation is too severe. If we extend a `CoffeeMachine`, we may have legitimate reason to access its internals. That's why protected fields are used most of the time, even though they are not supported by the language syntax.
Remember, usually we can access fields by this[name]:
265
+
如我们所知,通常我们可以使用 `this[name]` 访问字段:
280
266
281
267
```js
282
268
class User {
283
269
...
284
270
sayHi() {
285
271
let fieldName = "name";
286
-
alert(`Hello, ${this[fieldName]}`);
272
+
alert(`Hello, ${*!*this[fieldName]*/!*}`);
287
273
}
288
274
}
289
275
```
290
276
291
-
With private fields that's impossible: `this['#name']` doesn't work. That's a syntax limitation to ensure privacy.
277
+
私有字段是不可能的: `this['#name']` 不起作用。这是确保私有性的语法限制。
292
278
````
293
279
294
-
## Summary
280
+
## 总结
295
281
296
-
In terms of OOP, delimiting of the internal interface from the external one is called [encapsulation]("https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)").
Protection for users, so that they don't shoot themselves in the feet
301
-
: Imagine, there's a team of developers using a coffee machine. It was made by the "Best CoffeeMachine" company, and works fine, but a protective cover was removed. So the internal interface is exposed.
All developers are civilized -- they use the coffee machine as intended. But one of them, John, decided that he's the smartest one, and made some tweaks in the coffee machine internals. So the coffee machine failed two days later.
That's surely not John's fault, but rather the person who removed the protective cover and let John do his manipulations.
291
+
这肯定不是约翰的错,而是那个取下保护套并让约翰执行自己操作的人的错。
306
292
307
-
The same in programming. If a user of a class will change things not intended to be changed from the outside -- the consequences are unpredictable.
293
+
编程也一样。如果一个类的使用者想要改变那些本不打算从外部改变的东西 —— 后果是不可预测的。
308
294
309
-
Supportable
310
-
: The situation in programming is more complex than with a real-life coffee machine, because we don't just buy it once. The code constantly undergoes development and improvement.
295
+
可支持的
296
+
: 编程的情况比现实生活中的咖啡机更复杂,因为我们不只是购买一次。代码不断经历着发展和改进。
311
297
312
-
**If we strictly delimit the internal interface, then the developer of the class can freely change its internal properties and methods, even without informing the users..**
It's much easier to develop, if you know that certain methods can be renamed, their parameters can be changed, and even removed, because no external code depends on them.
For users, when a new version comes out, it may be a total overhaul, but still simple to upgrade if the external interface is the same.
302
+
对于使用者来说,当新版本出现时,它可能是全面的内部检查,但如果外部接口相同,则仍然很容易升级。
317
303
318
-
Hiding complexity
319
-
: People adore to use things that are simple. At least from outside. What's inside is a different thing.
304
+
隐藏复杂性
305
+
: 人们喜欢使用简单的东西。至少从外部来看是这样。内部的东西则是另外一回事了。
320
306
321
-
Programmers are not an exception.
307
+
程序员也不例外。
322
308
323
-
**It's always convenient when implementation details are hidden, and a simple, well-documented external interface is available.**
309
+
**隐藏实施细节时总是很方便,并且提供了一个简单的,记录详细的外部接口。**
324
310
325
-
To hide internal interface we use either protected or public properties:
311
+
为了隐藏内部接口,我们使用受保护的或私有的属性:
326
312
327
-
-Protected fields start with `_`. That's a well-known convention, not enforced at the language level. Programmers should only access a field starting with `_`from its class and classes inheriting from it.
328
-
-Private fields start with `#`. JavaScript makes sure we only can access those from inside the class.
0 commit comments