AngularJS: Khi nào nên sử dụng dịch vụ thay vì nhà máy


296

Hãy chịu đựng với tôi ở đây. Tôi biết có những câu trả lời khác như: AngularJS: Service vs nhà cung cấp vs nhà máy

Tuy nhiên tôi vẫn không thể hiểu khi nào bạn sử dụng dịch vụ tại nhà máy.

Từ những gì tôi có thể nói với nhà máy thường được sử dụng để tạo các hàm "chung" có thể được gọi bởi nhiều Bộ điều khiển: Tạo các hàm điều khiển chung

Các tài liệu Angular dường như thích nhà máy hơn dịch vụ. Họ thậm chí còn đề cập đến "dịch vụ" khi họ sử dụng nhà máy thậm chí còn khó hiểu hơn! http://docs.angularjs.org/guide/dev_guide.service.creating_service

Vậy khi nào thì một người sẽ sử dụng dịch vụ?

Có điều gì đó chỉ có thể hoặc dễ dàng hơn được thực hiện với dịch vụ?

Có điều gì khác biệt xảy ra đằng sau hậu trường không? Hiệu suất / bộ nhớ khác nhau?

Đây là một ví dụ. Khác với phương pháp khai báo, chúng có vẻ giống hệt nhau và tôi không thể hiểu tại sao tôi lại làm cái này với cái kia. http://jsfiddle.net/uEpkE/

Cập nhật: Từ câu trả lời của Thomas, dường như ngụ ý rằng dịch vụ dành cho logic đơn giản hơn và nhà máy cho logic phức tạp hơn với các phương thức riêng tư, vì vậy tôi đã cập nhật mã fiddle bên dưới và dường như cả hai đều có thể hỗ trợ các chức năng riêng tư?

myApp.factory('fooFactory', function() {
    var fooVar;
    var addHi = function(foo){ fooVar = 'Hi '+foo; }

    return {
        setFoobar: function(foo){
            addHi(foo);
        },
        getFoobar:function(){
            return fooVar;
        }
    };
});
myApp.service('fooService', function() {
    var fooVar;
    var addHi = function(foo){ fooVar = 'Hi '+foo;}

    this.setFoobar = function(foo){
        addHi(foo);
    }
    this.getFoobar = function(){
        return fooVar;
    }
});

function MyCtrl($scope, fooService, fooFactory) {
    fooFactory.setFoobar("fooFactory");
    fooService.setFoobar("fooService");
    //foobars = "Hi fooFactory, Hi fooService"
    $scope.foobars = [
        fooFactory.getFoobar(),
        fooService.getFoobar()
    ];
}

tất nhiên dịch vụ hỗ trợ riêng tư nhưng nếu bạn đọc chính xác bài đăng của tôi thì đó hoàn toàn là kiểu mã: chúng ta cũng có thể tận dụng phạm vi từ vựng mới để mô phỏng các biến "riêng tư". Đó là "SIMULATE"
Thomas Pons

Tôi thấy cuộc thảo luận này rất hữu ích stackoverflow.com/questions/15666048/ từ
Anand Gupta

Câu trả lời:


280

Giải trình

Bạn có những thứ khác nhau ở đây:

Đầu tiên:

  • Nếu bạn sử dụng một dịch vụ, bạn sẽ nhận được ví dụ của một hàm (" this" từ khóa).
  • Nếu bạn sử dụng một nhà máy, bạn sẽ nhận được giá trị được trả về bằng cách gọi tham chiếu hàm (câu lệnh return trong nhà máy).

ref: angular.service vs angular.factory

Thứ hai:

Hãy ghi nhớ tất cả các nhà cung cấp trong AngularJS (giá trị, hằng số, dịch vụ, nhà máy) là những người độc thân!

Ngày thứ ba:

Sử dụng cái này hay cái kia (dịch vụ hoặc nhà máy) là về kiểu mã. Nhưng, cách phổ biến trong AngularJS là sử dụng nhà máy .

Tại sao ?

Bởi vì "Phương thức nhà máy là cách phổ biến nhất để đưa các đối tượng vào hệ thống tiêm phụ thuộc AngularJS. Nó rất linh hoạt và có thể chứa logic sáng tạo tinh vi. Vì các nhà máy là các chức năng thông thường, chúng tôi cũng có thể tận dụng phạm vi từ vựng mới để mô phỏng" riêng tư "biến. Điều này rất hữu ích vì chúng ta có thể ẩn chi tiết triển khai của một dịch vụ nhất định."

(tham khảo : http://www.amazon.com/Mastering-Web-Application-Development-AngularJS/dp/1782161821 ).


Sử dụng

Dịch vụ: Có thể hữu ích để chia sẻ các chức năng tiện ích hữu ích để gọi bằng cách thêm ()vào tham chiếu chức năng được chèn. Cũng có thể được chạy với injectedArg.call(this)hoặc tương tự.

Factory: Có thể hữu ích cho việc trả về một hàm 'class' mà sau đó có thể được tạo mới để tạo các thể hiện.

Vì vậy, hãy sử dụng một nhà máy khi bạn có logic phức tạp trong dịch vụ của mình và bạn không muốn phơi bày sự phức tạp này .

Trong các trường hợp khác, nếu bạn muốn trả về một thể hiện của dịch vụ, chỉ cần sử dụng dịch vụ .

Nhưng bạn sẽ thấy theo thời gian rằng bạn sẽ sử dụng nhà máy trong 80% trường hợp tôi nghĩ.

Để biết thêm chi tiết: http://blog.manishchhabra.com/2013/09/angularjs-service-vs-factory-with-example/


CẬP NHẬT:

Bài đăng tuyệt vời tại đây: http://iffycan.blogspot.com.ar/2013/05/angular-service-or-factory.html

"Nếu bạn muốn chức năng của mình được gọi như một chức năng bình thường , hãy sử dụng nhà máy . Nếu bạn muốn chức năng của mình được khởi tạo với toán tử mới, hãy sử dụng dịch vụ. Nếu bạn không biết sự khác biệt, hãy sử dụng nhà máy."


CẬP NHẬT:

Nhóm AngularJS thực hiện công việc của mình và đưa ra lời giải thích: http://docs.angularjs.org/guide/providers

Và từ trang này:

"Factory and Service là các công thức được sử dụng phổ biến nhất. Sự khác biệt duy nhất giữa chúng là Công thức dịch vụ hoạt động tốt hơn cho các đối tượng thuộc loại tùy chỉnh, trong khi Factory có thể tạo ra các hàm và nguyên hàm JavaScript."


7
Re First: Tôi đọc nó ở khắp mọi nơi nhưng tôi không hiểu ý nghĩa thực tế của nó. Tôi đoán từ câu trả lời của bạn không có sự khác biệt thực tế "đối với hầu hết các phần"? Cảm ơn các cuốn sách tham khảo mặc dù!
dùng1941747

Thật đơn giản nếu dịch vụ của bạn thực sự phức tạp và bạn cần các phương thức và đối tượng riêng tư sử dụng một nhà máy
Thomas Pons

1
Tôi nhận thấy bạn đã thêm "Nếu bạn muốn trả về một phiên bản của dịch vụ, chỉ cần sử dụng dịch vụ". Câu hỏi tiếp theo của tôi sẽ là KHI NÀO bạn muốn trả lại một phiên bản của dịch vụ? Tôi đang cố gắng tìm một trường hợp sử dụng cụ thể ở đây.
dùng1941747

12
"Vì các nhà máy là các chức năng thông thường, chúng tôi cũng có thể tận dụng phạm vi từ vựng mới để mô phỏng các biến" riêng tư ". - điều này không dành riêng cho các nhà máy, bạn có thể làm tương tự với các dịch vụ ..
pootzko

Có vẻ như nhóm google thích dịch vụ hơn nhà máy, điều này làm cho mọi thứ trở nên khó hiểu hơn! google-styleguide.googlecode.com/svn/trunk/ từ
xzhang

111

allernhwkim ban đầu đã đăng một câu trả lời cho câu hỏi này liên kết đến blog của mình , tuy nhiên một người điều hành đã xóa nó. Đó là bài đăng duy nhất tôi tìm thấy không chỉ cho bạn biết cách làm điều tương tự với dịch vụ, nhà cung cấp và nhà máy, mà còn cho bạn biết bạn có thể làm gì với nhà cung cấp mà bạn không thể làm với nhà máy và với một nhà máy mà bạn không thể có dịch vụ.

Trực tiếp từ blog của mình:

app.service('CarService', function() {
   this.dealer="Bad";
    this.numCylinder = 4;
});

app.factory('CarFactory', function() {
    return function(numCylinder) {
      this.dealer="Bad";
        this.numCylinder = numCylinder
    };
});

app.provider('CarProvider', function() {
    this.dealerName = 'Bad';
    this.$get = function() {
        return function(numCylinder) {
            this.numCylinder = numCylinder;
            this.dealer = this.dealerName;
        }
    };
    this.setDealerName = function(str) {
      this.dealerName = str;
    }      
});

Điều này cho thấy CarService sẽ luôn sản xuất một chiếc xe có 4 xi-lanh, bạn không thể thay đổi nó cho từng chiếc xe. Trong khi đó CarFactory trả về một chức năng để bạn có thể thực hiện new CarFactorytrong bộ điều khiển của mình, chuyển qua một số xi lanh dành riêng cho chiếc xe đó. Bạn không thể làm new CarServicevì CarService là một đối tượng không phải là một chức năng.

Lý do các nhà máy không hoạt động như thế này:

app.factory('CarFactory', function(numCylinder) {
      this.dealer="Bad";
      this.numCylinder = numCylinder
});

Và tự động trả về một hàm để bạn khởi tạo, là bởi vì sau đó bạn không thể làm điều này (thêm các thứ vào nguyên mẫu / etc):

app.factory('CarFactory', function() {
    function Car(numCylinder) {
        this.dealer="Bad";
        this.numCylinder = numCylinder
    };
    Car.prototype.breakCylinder = function() {
        this.numCylinder -= 1;
    };
    return Car;
});

Xem làm thế nào nó thực sự là một nhà máy sản xuất một chiếc xe hơi.

Kết luận từ blog của anh ấy là khá tốt:

Tóm lại là,

---------------------------------------------------  
| Provider| Singleton| Instantiable | Configurable|
---------------------------------------------------  
| Factory | Yes      | Yes          | No          |
---------------------------------------------------  
| Service | Yes      | No           | No          |
---------------------------------------------------  
| Provider| Yes      | Yes          | Yes         |       
---------------------------------------------------  
  1. Sử dụng Dịch vụ khi bạn chỉ cần một đối tượng đơn giản, chẳng hạn như Hash, ví dụ {foo; 1, bar: 2} Thật dễ dàng để viết mã, nhưng bạn không thể khởi tạo nó.

  2. Sử dụng Factory khi bạn cần khởi tạo một đối tượng, tức là Khách hàng mới (), Nhận xét mới (), v.v.

  3. Sử dụng Nhà cung cấp khi bạn cần cấu hình nó. tức là url kiểm tra, url QA, url sản xuất.

Nếu bạn thấy bạn vừa trả lại một đối tượng trong nhà máy, có lẽ bạn nên sử dụng dịch vụ.

Đừng làm điều này:

app.factory('CarFactory', function() {
    return {
        numCylinder: 4
    };
});

Sử dụng dịch vụ thay thế:

app.service('CarService', function() {
    this.numCylinder = 4;
});

11
nó rất hữu ích cho tôi +1 cho bảng so sánh
Vũ Anh

5
nếu bạn xác định chức năng dịch vụ với một tham số numCylinder thì nó sẽ có tính linh hoạt giống như phương thức xuất xưởng
Ovi

đi và đọc blog bài đăng, và lãng phí thời gian của bạn để cố gắng tìm ra góc cạnh, nếu bạn biết javascript sau khi đọc bài đăng này, bạn sẽ hoàn toàn hiểu sự khác biệt giữa điều này.
ncubica

4
Rất ngạc nhiên ! Bạn đang đề cập đến một blog ở đây và cả hai đang nói điều hoàn toàn trái ngược. Bạn nói: Nhà máy - Ngay lập tức - Có Blog nói: Nhà máy - Ngay lập tức - Không
Devesh M

1
Tôi đồng ý với @Devesh. Tôi nghĩ rằng bạn có ngay lập tức trộn lẫn. Từ bài đăng trên blog: "Chỉ với nhà máy, bạn không thể đạt được điều này vì nhà máy không thể khởi tạo được".
Matt

20

Khái niệm cho tất cả các nhà cung cấp này đơn giản hơn nhiều so với ban đầu. Nếu bạn mổ xẻ một nhà cung cấp cho bạn và rút ra các phần khác nhau, nó sẽ trở nên rất rõ ràng.

Nói một cách đơn giản là mỗi một trong số các nhà cung cấp là một phiên bản đặc biệt của người kia, theo thứ tự này: provider> factory> value/ constant/ service.

Vì vậy, nhà cung cấp sẽ làm những gì bạn có thể sử dụng nhà cung cấp trong chuỗi tiếp theo, điều này sẽ dẫn đến việc viết ít mã hơn. Nếu nó không thực hiện được những gì bạn muốn, bạn có thể đi lên chuỗi và bạn sẽ phải viết thêm mã.

Hình ảnh này minh họa ý tôi muốn nói, trong hình ảnh này, bạn sẽ thấy mã cho nhà cung cấp, với các phần được tô sáng cho bạn biết phần nào của nhà cung cấp có thể được sử dụng để tạo nhà máy, giá trị, v.v.

Các nhà cung cấp, nhà máy, dịch vụ của AngularJS đều giống nhau
(nguồn: Simplygoodcode.com )

Để biết thêm chi tiết và ví dụ từ bài đăng trên blog nơi tôi đã nhận được hình ảnh, hãy truy cập: http://www.simplygoodcode.com/2015/11/the-difference-b between-service-provider- and -actory-in- angularjs /


8

Cả nhà máy và dịch vụ đều dẫn đến các đối tượng đơn lẻ có thể được cấu hình bởi các nhà cung cấp và đưa vào bộ điều khiển và chạy các khối. Từ quan điểm của người được tiêm, hoàn toàn không có sự khác biệt cho dù đối tượng đến từ một nhà máy hay một dịch vụ.

Vậy, khi nào nên sử dụng nhà máy, và khi nào nên sử dụng dịch vụ? Nó sôi theo sở thích mã hóa của bạn, và không có gì khác. Nếu bạn thích mô hình JS mô-đun thì hãy đến nhà máy. Nếu bạn thích kiểu hàm tạo ("class") thì hãy tìm dịch vụ. Lưu ý rằng cả hai phong cách đều hỗ trợ các thành viên tư nhân.

Ưu điểm của dịch vụ có thể là trực quan hơn từ quan điểm OOP: tạo "lớp" và kết hợp với nhà cung cấp, sử dụng lại cùng một mã trên các mô-đun và thay đổi hành vi của các đối tượng được khởi tạo chỉ bằng cách cung cấp các tham số khác nhau cho hàm tạo trong một khối cấu hình.


Bạn có thể cung cấp một ví dụ về ý nghĩa của bạn bằng cách cung cấp các tham số khác nhau cho hàm tạo trong khối cấu hình không? Làm thế nào để bạn cung cấp các tham số nếu nó chỉ là một dịch vụ hoặc nhà máy. Bạn có ý nghĩa gì khi "kết hợp với một nhà cung cấp"? Việc có thể định cấu hình nó khiến tôi nghĩ rằng rất nhiều đối tượng của mình nên là nhà cung cấp so với các nhà máy hoặc dịch vụ.
âm sắc

2

Không có gì Nhà máy không thể làm hoặc làm tốt hơn so với Dịch vụ. Và ngược lại. Nhà máy dường như được phổ biến hơn. Lý do cho điều đó là sự thuận tiện của nó trong việc xử lý các thành viên tư nhân / công cộng. Dịch vụ sẽ vụng về hơn trong vấn đề này. Khi mã hóa một Dịch vụ, bạn có xu hướng làm cho các thành viên đối tượng của mình công khai thông qua từ khóa này và có thể bất ngờ phát hiện ra rằng các thành viên công cộng đó không hiển thị với các phương thức riêng tư (tức là các hàm bên trong).

var Service = function(){

  //public
  this.age = 13;

  //private
  function getAge(){

    return this.age; //private does not see public

  }

  console.log("age: " + getAge());

};

var s = new Service(); //prints 'age: undefined'

Angular sử dụng từ khóa mới của Mt để tạo một dịch vụ cho bạn, do đó, Angular chuyển đến bộ điều khiển sẽ có cùng một nhược điểm. Tất nhiên bạn có thể khắc phục vấn đề bằng cách sử dụng cái này / cái kia:

var Service = function(){

  var that = this;

  //public
  this.age = 13;

  //private
  function getAge(){

    return that.age;

  }

  console.log("age: " + getAge());

};

var s = new Service();// prints 'age: 13'  

Nhưng với hằng số Dịch vụ lớn, điều này sẽ khiến mã không thể đọc được. Ngoài ra, các nguyên mẫu Dịch vụ sẽ không thấy các thành viên tư nhân - chỉ công khai mới có sẵn cho họ:

var Service = function(){

  var name = "George";

};

Service.prototype.getName = function(){

  return this.name; //will not see a private member

};

var s = new Service();
console.log("name: " + s.getName());//prints 'name: undefined'

Tổng kết lại, sử dụng Factory thuận tiện hơn. Vì Nhà máy không có những hạn chế. Tôi sẽ khuyên bạn nên sử dụng nó theo mặc định.


Câu trả lời này có một số vấn đề. Đầu tiên, bài đăng này thể hiện khái niệm về phạm vi từ vựng của Javascript thay vì cách các dịch vụ AngularJS hoạt động. Thứ hai bối cảnh của cuộc gọi myapp.service(...)bị thiếu hoàn toàn. Trường hợp new Service()được gọi là, trong chức năng dịch vụ hoặc tại nơi Dịch vụ được tiêm. Danh sách thứ ba đơn giản là không thể trong bối cảnh myapp.service ('Service', function() {...}).
lanoxx

2

Ngay cả khi họ nói rằng tất cả các dịch vụ và nhà máy đều là đơn lẻ, tôi không đồng ý 100% với điều đó. Tôi muốn nói rằng các nhà máy không phải là singletons và đây là điểm trả lời của tôi. Tôi thực sự sẽ nghĩ về cái tên xác định mọi thành phần (Dịch vụ / Nhà máy), ý tôi là:

Một nhà máy vì không phải là một singleton, bạn có thể tạo bao nhiêu tùy ý khi bạn tiêm, vì vậy nó hoạt động giống như một nhà máy của các đối tượng. Bạn có thể tạo một nhà máy của một thực thể trong miền của bạn và làm việc thoải mái hơn với các đối tượng này có thể giống như một đối tượng của mô hình của bạn. Khi bạn truy xuất một số đối tượng, bạn có thể ánh xạ chúng trong các đối tượng này và nó có thể hoạt động giống như một lớp khác giữa mô hình DDBB và AngularJs. Bạn có thể thêm các phương thức vào các đối tượng để bạn định hướng cho các đối tượng nhiều hơn một chút Ứng dụng AngularJs của bạn.

Trong khi đó một dịch vụ là một đơn vị, vì vậy chúng tôi chỉ có thể tạo 1 loại, có thể không tạo nhưng chúng tôi chỉ có 1 phiên bản khi chúng tôi tiêm vào bộ điều khiển, vì vậy một dịch vụ cung cấp giống như một dịch vụ chung (các cuộc gọi còn lại, chức năng ..) để các bộ điều khiển.

Về mặt khái niệm bạn có thể nghĩ như các dịch vụ cung cấp một dịch vụ, các nhà máy có thể tạo ra nhiều thể hiện (đối tượng) của một lớp


0

Dịch vụ

Cú pháp : module.service ('serviceName', function); Kết quả : Khi khai báo serviceName dưới dạng đối số có thể tiêm, bạn sẽ được cung cấp tham chiếu hàm thực tế được truyền cho module.service.

Cách sử dụng : Có thể hữu ích cho việc chia sẻ các hàm tiện ích hữu ích để gọi bằng cách thêm () vào tham chiếu hàm được chèn. Cũng có thể được chạy với in tiêmArg.call (cái này) hoặc tương tự.

Các nhà máy

Cú pháp : module.factory ('FactoryName', function);

Kết quả : Khi khai báo FactoryName là một đối số có thể tiêm, bạn sẽ được cung cấp giá trị được trả về bằng cách gọi tham chiếu hàm được truyền cho module.factory.

Cách sử dụng : Có thể hữu ích cho việc trả về một hàm 'lớp' mà sau đó có thể được tạo mới để tạo các thể hiện.

Nhà cung cấp

Cú pháp : module.provider ('CarrierName', function);

Kết quả : Khi khai báo tên nhà cung cấp dưới dạng đối số có thể tiêm, bạn sẽ được cung cấp giá trị được trả về bằng cách gọi phương thức $ get của tham chiếu hàm được truyền cho module.provider.

Cách sử dụng : Có thể hữu ích cho việc trả về một hàm 'lớp' mà sau đó có thể được tạo mới để tạo các thể hiện nhưng yêu cầu một số loại cấu hình trước khi được đưa vào. Có lẽ hữu ích cho các lớp có thể tái sử dụng trên các dự án? Vẫn còn mơ hồ về điều này.


0

Có thể sử dụng cả hai cách bạn muốn : cho dù tạo đối tượng hay j ust để truy cập các chức năng từ cả hai


Bạn có thể tạo đối tượng mới từ dịch vụ

app.service('carservice', function() {
    this.model = function(){
        this.name = Math.random(22222);
        this.price = 1000;
        this.colour = 'green';
        this.manufacturer = 'bmw';
    }
});

.controller('carcontroller', function ($scope,carservice) { 
    $scope = new carservice.model();
})

Ghi chú :

  • dịch vụ theo mặc định trả về đối tượng và không phải hàm xây dựng.
  • Vì vậy, đó là lý do tại sao hàm constructor được đặt thành thuộc tính this.model.
  • Do dịch vụ này sẽ trả về đối tượng, nhưng bên trong đối tượng đó sẽ là hàm xây dựng sẽ được sử dụng để tạo đối tượng mới;

Bạn có thể tạo đối tượng mới từ nhà máy

app.factory('carfactory', function() {
    var model = function(){
        this.name = Math.random(22222);
        this.price = 1000;
        this.colour = 'green';
        this.manufacturer = 'bmw';
    }
    return model;
});

.controller('carcontroller', function ($scope,carfactory) { 
    $scope = new carfactory();
})

Ghi chú :

  • Nhà máy mặc định trả về hàm constructor và không phải đối tượng.
  • Vì vậy, đó là lý do tại sao đối tượng mới có thể được tạo bằng chức năng xây dựng.

Tạo dịch vụ chỉ cần truy cập các chức năng đơn giản

app.service('carservice', function () {
   this.createCar = function () {
       console.log('createCar');
   };
   this.deleteCar = function () {
       console.log('deleteCar');
   };
});

.controller('MyService', function ($scope,carservice) { 
    carservice.createCar()
})

Tạo nhà máy chỉ để truy cập các chức năng đơn giản

app.factory('carfactory', function () {
    var obj = {} 
        obj.createCar = function () {
            console.log('createCar');
        };
       obj.deleteCar = function () {
       console.log('deleteCar');
    };
});

.controller('MyService', function ($scope,carfactory) { 
    carfactory.createCar()
})

Phần kết luận :

  • bạn có thể sử dụng cả hai cách bạn muốn để tạo đối tượng mới hay chỉ để truy cập các chức năng đơn giản
  • Sẽ không có bất kỳ hiệu suất nào, sử dụng cái này hơn cái kia
  • Cả hai đều là đối tượng singleton và chỉ có một phiên bản được tạo cho mỗi ứng dụng.
  • Chỉ là một ví dụ mỗi khi tham chiếu của họ được thông qua.
  • Trong nhà máy tài liệu góc được gọi là dịch vụdịch vụ cũng được gọi là dịch vụ .

0

Nhà máy và Dịch vụ là phương pháp được sử dụng phổ biến nhất. Sự khác biệt duy nhất giữa chúng là phương thức Dịch vụ hoạt động tốt hơn cho các đối tượng cần phân cấp kế thừa, trong khi Nhà máy có thể tạo ra các hàm và hàm nguyên gốc JavaScript.

Hàm Nhà cung cấp là phương thức cốt lõi và tất cả các hàm khác chỉ là cú pháp cú pháp trên đó. Bạn chỉ cần nó nếu bạn đang xây dựng một đoạn mã có thể tái sử dụng cần cấu hình toàn cầu.

Có năm phương pháp để tạo ra các dịch vụ: Giá trị, Nhà máy, Dịch vụ, Nhà cung cấp và Hằng số. Bạn có thể tìm hiểu thêm về dịch vụ này ở đây , bài viết này giải thích tất cả các phương pháp này với các ví dụ demo thực tế.

.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.