Skip to content

Commit 344a04a

Browse files
committed
Translate 5-Classes: SOLID part
1 parent 9846c4d commit 344a04a

File tree

1 file changed

+90
-87
lines changed

1 file changed

+90
-87
lines changed

README.md

Lines changed: 90 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Original Repository: [ryanmcdermott/clean-code-javascript](https://github.com/ry
77
2. [Biến](#biến)
88
3. [Functions](#functions)
99
4. [Đối tượng và Cấu trúc dữ liệu](#đối-tượng-và-cấu-trúc-dữ-liệu)
10-
5. [Classes](#classes)
10+
5. [Lớp](#lớp)
1111
6. [Testing](#testing)
1212
7. [Xử lí đồng thời](#xử-lí-đồng-thời)
1313
8. [Xử lí lỗi](#xử-lí-lỗi)
@@ -1025,18 +1025,18 @@ console.log(`Employee name: ${employee.getName()}`); // Employee name: John Doe
10251025
**[⬆ về đầu trang](#mục-lục)**
10261026

10271027

1028-
## **Classes**
1029-
### Single Responsibility Principle (SRP)
1030-
As stated in Clean Code, "There should never be more than one reason for a class
1031-
to change". It's tempting to jam-pack a class with a lot of functionality, like
1032-
when you can only take one suitcase on your flight. The issue with this is
1033-
that your class won't be conceptually cohesive and it will give it many reasons
1034-
to change. Minimizing the amount of times you need to change a class is important.
1035-
It's important because if too much functionality is in one class and you modify a piece of it,
1036-
it can be difficult to understand how that will affect other dependent modules in
1037-
your codebase.
1028+
## **Lớp**
1029+
### Nguyên lí đơn trách nhiệm (Single Responsibility Principle)
1030+
Như đã được nói đến trong cuốn Clean Code, "Chỉ có thể thay đổi một lớp vì một lí
1031+
do duy nhất". Thật là hấp dẫn để nhồi nhét nhiều chức năng vào cho một lớp, giống
1032+
như là khi bạn chỉ có thể lấy một chiếc vali cho chuyến bay vậy. Vấn đề là lớp của
1033+
bạn sẽ không được hiểu gắn kết về mặt khái niệm của nó và sẽ có rất nhiều lí do
1034+
để thay đổi. Việc làm giảm thiểu số lần bạn cần phải thay đổi một lớp là một việc
1035+
quan trọng. Nó quan trọng bởi vì nếu có quá nhiều chức năng trong một lớp và bạn
1036+
chỉ muốn thay đổi một chút xíu của lớp đó, thì có thể sẽ rất khó để hiểu được việc
1037+
thay đổi đó sẽ ảnh hưởng đến những module khác trong codebase của bạn như thế nào.
10381038

1039-
**Bad:**
1039+
**Không tốt:**
10401040
```javascript
10411041
class UserSettings {
10421042
constructor(user) {
@@ -1055,7 +1055,7 @@ class UserSettings {
10551055
}
10561056
```
10571057

1058-
**Good:**
1058+
**Tốt:**
10591059
```javascript
10601060
class UserAuth {
10611061
constructor(user) {
@@ -1081,15 +1081,15 @@ class UserSettings {
10811081
}
10821082
}
10831083
```
1084-
**[back to top](#mục-lục)**
1084+
**[về đầu trang](#mục-lục)**
10851085

1086-
### Open/Closed Principle (OCP)
1087-
As stated by Bertrand Meyer, "software entities (classes, modules, functions,
1088-
etc.) should be open for extension, but closed for modification." What does that
1089-
mean though? This principle basically states that you should allow users to
1090-
add new functionalities without changing existing code.
1086+
### Nguyên lí đóng mở (Open/Closed Principle)
1087+
Betrand Meyer đã nói "có thể thoải mái mở rộng một module, nhưng hạn chế sửa
1088+
đổi bên trong module đó". Điều đó nghĩa là gì? Nguyên tắc này cơ bản nhấn mạnh
1089+
rằng bạn phải cho phép người dùng thêm các chức năng mới mà không làm thay
1090+
đổi các code đang có.
10911091

1092-
**Bad:**
1092+
**Không tốt:**
10931093
```javascript
10941094
class AjaxAdapter extends Adapter {
10951095
constructor() {
@@ -1132,7 +1132,7 @@ function makeHttpCall(url) {
11321132
}
11331133
```
11341134

1135-
**Good:**
1135+
**Tốt:**
11361136
```javascript
11371137
class AjaxAdapter extends Adapter {
11381138
constructor() {
@@ -1168,24 +1168,26 @@ class HttpRequester {
11681168
}
11691169
}
11701170
```
1171-
**[back to top](#mục-lục)**
1171+
**[về đầu trang](#mục-lục)**
11721172

11731173

1174-
### Liskov Substitution Principle (LSP)
1175-
This is a scary term for a very simple concept. It's formally defined as "If S
1176-
is a subtype of T, then objects of type T may be replaced with objects of type S
1177-
(i.e., objects of type S may substitute objects of type T) without altering any
1178-
of the desirable properties of that program (correctness, task performed,
1179-
etc.)." That's an even scarier definition.
1174+
### Nguyên lí thay thế Liskov (Liskov Substitution Principle)
1175+
Đây là một thuật ngữ đáng sợ cho một khái niệm rất đơn giản. Nó được định nghĩa
1176+
một cách chính thức là: "Nếu S là một kiểu con của T, thì các đối tượng của kiểu
1177+
T có thể được thay thế bằng các đối tượng của kiểu S (ví dụ các đối tượng của
1178+
kiểu S có thể thay thế các đối tượng của kiểu T) mà không làm thay đổi bất kì thuộc
1179+
tính mong muốn nào của chương trình đó (tính chính xác, thực hiện tác vụ, ..).
1180+
Đó thậm chí còn là một định nghĩa đáng sợ hơn.
11801181

1181-
The best explanation for this is if you have a parent class and a child class,
1182-
then the base class and child class can be used interchangeably without getting
1183-
incorrect results. This might still be confusing, so let's take a look at the
1184-
classic Square-Rectangle example. Mathematically, a square is a rectangle, but
1185-
if you model it using the "is-a" relationship via inheritance, you quickly
1186-
get into trouble.
1182+
Sự giải thích tốt nhất cho nguyên lí này là, nếu bạn có một lớp cha và một lớp con,
1183+
thì lớp cơ sở và lớp con có thể được sử dụng thay thế cho nhau mà không làm thay
1184+
đổi tính đúng đắn của chương trình. Có thể vẫn còn hơi rối ở đây, vậy hãy xem
1185+
cái ví dụ cổ điển hình vuông-hình chữ nhật (Square-Rectangle) dưới đây. Về mặt
1186+
toán học, một hình vuông là một hình chữ nhật, tuy nhiên nếu bạn mô hình hoá điều
1187+
này sử dụng quan hệ "is a" thông qua việc kế thừa, bạn sẽ nhanh chóng gặp phải
1188+
rắc rối đấy.
11871189

1188-
**Bad:**
1190+
**Không tốt:**
11891191
```javascript
11901192
class Rectangle {
11911193
constructor() {
@@ -1239,7 +1241,7 @@ const rectangles = [new Rectangle(), new Rectangle(), new Square()];
12391241
renderLargeRectangles(rectangles);
12401242
```
12411243

1242-
**Good:**
1244+
**Tốt:**
12431245
```javascript
12441246
class Shape {
12451247
setColor(color) {
@@ -1305,23 +1307,25 @@ function renderLargeShapes(shapes) {
13051307
const shapes = [new Rectangle(), new Rectangle(), new Square()];
13061308
renderLargeShapes(shapes);
13071309
```
1308-
**[back to top](#mục-lục)**
1310+
**[về đầu trang](#mục-lục)**
13091311

1310-
### Interface Segregation Principle (ISP)
1311-
JavaScript doesn't have interfaces so this principle doesn't apply as strictly
1312-
as others. However, it's important and relevant even with JavaScript's lack of
1313-
type system.
1312+
### Nguyên lí phân tách interface (Interface Segregation Principle)
13141313

1315-
ISP states that "Clients should not be forced to depend upon interfaces that
1316-
they do not use." Interfaces are implicit contracts in JavaScript because of
1317-
duck typing.
1314+
JavaScript không có interface vì vậy nguyên lí này không áp dụng một cách
1315+
chặt chẽ như các nguyên lí khác. Tuy nhiên, nó cũng quan trọng và liên quan
1316+
ngay cả với hệ thống thiếu định kiểu của JavaScript.
13181317

1319-
A good example to look at that demonstrates this principle in JavaScript is for
1320-
classes that require large settings objects. Not requiring clients to setup
1321-
huge amounts of options is beneficial, because most of the time they won't need
1322-
all of the settings. Making them optional helps prevent having a "fat interface".
1318+
Nguyên lí phân tách interface nhấn mạnh rằng "Người dùng không nên bị bắt
1319+
buộc phải phụ thuộc vào các interfaces mà họ không sử dụng." Interface là
1320+
những ràng buộc ẩn trong JavaScript bởi vì duck typing.
13231321

1324-
**Bad:**
1322+
Một ví dụ tốt để minh hoạ cho nguyên lí này trong JavaScript là các lớp mà yêu
1323+
cầu cài đặt các đối tượng lớn. Việc không yêu cầu người dùng thiết lập một số
1324+
lượng lớn các tuỳ chọn là một ích lợi, bởi vì đa số thời gian họ không cần tất
1325+
cả các cài đặt. Làm cho chúng trở thành tuỳ chọn giúp tránh được việc có một
1326+
"fat interface".
1327+
1328+
**Không tốt:**
13251329
```javascript
13261330
class DOMTraverser {
13271331
constructor(settings) {
@@ -1347,7 +1351,7 @@ const $ = new DOMTraverser({
13471351

13481352
```
13491353

1350-
**Good:**
1354+
**Tốt:**
13511355
```javascript
13521356
class DOMTraverser {
13531357
constructor(settings) {
@@ -1379,30 +1383,29 @@ const $ = new DOMTraverser({
13791383
}
13801384
});
13811385
```
1382-
**[back to top](#mục-lục)**
1386+
**[về đầu trang](#mục-lục)**
13831387

1384-
### Dependency Inversion Principle (DIP)
1385-
This principle states two essential things:
1386-
1. High-level modules should not depend on low-level modules. Both should
1387-
depend on abstractions.
1388-
2. Abstractions should not depend upon details. Details should depend on
1389-
abstractions.
1390-
1391-
This can be hard to understand at first, but if you've worked with Angular.js,
1392-
you've seen an implementation of this principle in the form of Dependency
1393-
Injection (DI). While they are not identical concepts, DIP keeps high-level
1394-
modules from knowing the details of its low-level modules and setting them up.
1395-
It can accomplish this through DI. A huge benefit of this is that it reduces
1396-
the coupling between modules. Coupling is a very bad development pattern because
1397-
it makes your code hard to refactor.
1398-
1399-
As stated previously, JavaScript doesn't have interfaces so the abstractions
1400-
that are depended upon are implicit contracts. That is to say, the methods
1401-
and properties that an object/class exposes to another object/class. In the
1402-
example below, the implicit contract is that any Request module for an
1403-
`InventoryTracker` will have a `requestItems` method.
1388+
### Nguyên lí đảo ngược dependency (Dependency Inversion Principle)
1389+
Nguyên lí này khẳng định hai điều cần thiết sau:
1390+
1. Nhưng module cấp cao không nên phụ thuộc vào những module cấp thấp. Cả
1391+
hai nên phụ thuộc vào abstraction.
1392+
2. Abstraction (interface) không nên phụ thuộc vào chi tiết, mà ngược lại.
1393+
1394+
Điều này có thể khó hiểu lúc ban đầu, nhưng nếu bạn đã từng làm việc với Angular.js,
1395+
bạn đã thấy một sự hiện thực của nguyên lí này trong dạng của Dependency Injection
1396+
(DI). Khi chúng không phải là các khái niệm giống nhau, DIP giữ cho module cấp
1397+
cao không biết chi tiết các module cấp thấp của nó và thiết lập chúng. Có thể đạt
1398+
được điều này thông qua DI. Một lợi ích to lớn của DIP là nó làm giảm sự phụ thuộc
1399+
lẫn nhau giữa các module. Sự phụ thuộc lẫn nhau là một kiểu mẫu không tốt, vì nó
1400+
làm cho việc tái cấu trúc code trở nên khó khăn.
1401+
1402+
Như đã khẳng định ở trước, JavaScript không có interface vì vậy các abstraction
1403+
mà bị phụ thuộc là những ràng buộc ẩn. Đó là để nói, các phương thức và thuộc tính
1404+
mà một đối tượng/lớp làm phơi bày đối tượng/lớp khác. Trong ví dụ bên dưới, sự ràng
1405+
buộc ẩn là bất cứ module Request cho một `InventoryRequester` sẽ có một phương thức
1406+
`requestItems`.
14041407

1405-
**Bad:**
1408+
**Không tốt:**
14061409
```javascript
14071410
class InventoryRequester {
14081411
constructor() {
@@ -1418,8 +1421,8 @@ class InventoryTracker {
14181421
constructor(items) {
14191422
this.items = items;
14201423

1421-
// BAD: We have created a dependency on a specific request implementation.
1422-
// We should just have requestItems depend on a request method: `request`
1424+
// Không tốt: chúng ta đã tạo một phụ thuộc vào một hiện thực của một request cụ thể
1425+
// Chúng ta nên có những requestItems phụ thuộc vào một phương thức request `request`
14231426
this.requester = new InventoryRequester();
14241427
}
14251428

@@ -1434,7 +1437,7 @@ const inventoryTracker = new InventoryTracker(['apples', 'bananas']);
14341437
inventoryTracker.requestItems();
14351438
```
14361439

1437-
**Good:**
1440+
**Tốt:**
14381441
```javascript
14391442
class InventoryTracker {
14401443
constructor(items, requester) {
@@ -1469,20 +1472,20 @@ class InventoryRequesterV2 {
14691472
}
14701473
}
14711474

1472-
// By constructing our dependencies externally and injecting them, we can easily
1473-
// substitute our request module for a fancy new one that uses WebSockets.
1475+
// Bằng cách xây dựng các phụ thuộc ở ngoài và thêm chúng vào, chúng ta có thể
1476+
// dễ dàng thay thế module request bằng một module mới lạ sử dụng WebSockets.
14741477
const inventoryTracker = new InventoryTracker(['apples', 'bananas'], new InventoryRequesterV2());
14751478
inventoryTracker.requestItems();
14761479
```
1477-
**[back to top](#mục-lục)**
1480+
**[về đầu trang](#mục-lục)**
14781481

14791482
### Prefer ES2015/ES6 classes over ES5 plain functions
14801483
It's very difficult to get readable class inheritance, construction, and method
14811484
definitions for classical ES5 classes. If you need inheritance (and be aware
14821485
that you might not), then prefer classes. However, prefer small functions over
14831486
classes until you find yourself needing larger and more complex objects.
14841487

1485-
**Bad:**
1488+
**Không tốt:**
14861489
```javascript
14871490
const Animal = function(age) {
14881491
if (!(this instanceof Animal)) {
@@ -1521,7 +1524,7 @@ Human.prototype.constructor = Human;
15211524
Human.prototype.speak = function speak() {};
15221525
```
15231526

1524-
**Good:**
1527+
**Tốt:**
15251528
```javascript
15261529
class Animal {
15271530
constructor(age) {
@@ -1549,7 +1552,7 @@ class Human extends Mammal {
15491552
speak() { /* ... */ }
15501553
}
15511554
```
1552-
**[back to top](#mục-lục)**
1555+
**[về đầu trang](#mục-lục)**
15531556

15541557

15551558
### Use method chaining
@@ -1559,7 +1562,7 @@ For that reason, I say, use method chaining and take a look at how clean your co
15591562
will be. In your class functions, simply return `this` at the end of every function,
15601563
and you can chain further class methods onto it.
15611564

1562-
**Bad:**
1565+
**Không tốt:**
15631566
```javascript
15641567
class Car {
15651568
constructor() {
@@ -1592,7 +1595,7 @@ car.setModel('F-150');
15921595
car.save();
15931596
```
15941597

1595-
**Good:**
1598+
**Tốt:**
15961599
```javascript
15971600
class Car {
15981601
constructor() {
@@ -1632,7 +1635,7 @@ const car = new Car()
16321635
.setModel('F-150')
16331636
.save();
16341637
```
1635-
**[back to top](#mục-lục)**
1638+
**[về đầu trang](#mục-lục)**
16361639

16371640
### Prefer composition over inheritance
16381641
As stated famously in [*Design Patterns*](https://en.wikipedia.org/wiki/Design_Patterns) by the Gang of Four,
@@ -1652,7 +1655,7 @@ relationship (Human->Animal vs. User->UserDetails).
16521655
3. You want to make global changes to derived classes by changing a base class.
16531656
(Change the caloric expenditure of all animals when they move).
16541657

1655-
**Bad:**
1658+
**Không tốt:**
16561659
```javascript
16571660
class Employee {
16581661
constructor(name, email) {
@@ -1675,7 +1678,7 @@ class EmployeeTaxData extends Employee {
16751678
}
16761679
```
16771680

1678-
**Good:**
1681+
**Tốt:**
16791682
```javascript
16801683
class EmployeeTaxData {
16811684
constructor(ssn, salary) {
@@ -1698,7 +1701,7 @@ class Employee {
16981701
// ...
16991702
}
17001703
```
1701-
**[back to top](#mục-lục)**
1704+
**[về đầu trang](#mục-lục)**
17021705

17031706
## **Testing**
17041707
Testing thì quan trọng hơn shipping. Nếu bạn không có test hoặc không đủ,

0 commit comments

Comments
 (0)