Ý nghĩa của việc tiêm dữ liệu (so với hành vi) trong một hàm tạo của lớp và tại sao điều đó được coi là thực hành xấu?


10

Tôi đang đọc cuốn sách "Học tập TypeScript" của Remo Jansen. Trong một phần, tác giả mô tả cách tạo một khung MVC bằng chứng rất đơn giản bao gồm cách tạo Modellớp và nói như sau:

Một mô hình cần được cung cấp với URL của dịch vụ web mà nó tiêu thụ. Chúng tôi sẽ sử dụng một trình trang trí lớp có tên ModelSinstall để đặt URL của dịch vụ sẽ được sử dụng. Chúng ta có thể tiêm URL dịch vụ thông qua hàm tạo của nó, nhưng nó được coi là một hành vi xấu khi tiêm dữ liệu (trái ngược với hành vi) thông qua một hàm tạo của lớp .

Tôi không hiểu câu cuối cùng đó. Cụ thể, tôi không hiểu ý nghĩa của việc "tiêm dữ liệu". Đối với tôi, dường như trong hầu hết tất cả các giới thiệu về các lớp JavaScript sử dụng các ví dụ đơn giản hóa quá mức, dữ liệu được đưa vào ("được chèn"?) Vào hàm tạo thông qua các tham số của nó. Ví dụ:

class Person {
  constructor(name) {
    this.name = name;
  }
}

Tôi chắc chắn nghĩ về namedữ liệu, không phải là hành vi và nó được bao gồm phổ biến trong ví dụ này như là một tham số của hàm tạo, và không bao giờ có bất kỳ đề cập nào rằng đây là thực tiễn xấu. Do đó, tôi cho rằng tôi đang hiểu nhầm một cái gì đó trong đoạn trích dẫn trên, có nghĩa là "dữ liệu" hoặc "tiêm" hoặc một cái gì đó khác.

Câu trả lời của bạn có thể bao gồm các giải thích về thời điểm, địa điểm, cách thức và lý do sử dụng trang trí trong JavaScript / TypeScript, vì tôi nghi ngờ rằng khái niệm này có liên quan mật thiết đến sự hiểu biết mà tôi tìm kiếm. Tuy nhiên, quan trọng hơn, tôi muốn hiểu chung hơn về ý nghĩa của việc tiêm dữ liệu thông qua một trình xây dựng lớp và tại sao điều đó lại xấu.


Để cung cấp thêm ngữ cảnh cho trích dẫn ở trên, đây là tình huống: Một Modellớp được tạo ra, trong ví dụ này, sẽ được sử dụng để tạo các mô hình trao đổi chứng khoán, một cho NASDAQ và một cho NYSE. Mỗi mô hình yêu cầu đường dẫn của dịch vụ web hoặc tệp dữ liệu tĩnh sẽ cung cấp dữ liệu thô. Cuốn sách nói rằng một trang trí nên được sử dụng cho thông tin này, chứ không phải là một tham số của nhà xây dựng, dẫn đến những điều sau đây:

@ModelSettings("./data/nasdaq.json")
class NasdaqModel extends Model implements IModel {
  constructor(metiator : IMediator) {
    super(metiator);
  }
...
}

Tôi chỉ không hiểu tại sao tôi nên thêm url dịch vụ thông qua trình trang trí chứ không chỉ đơn giản là một tham số cho hàm tạo, ví dụ:

constructor(metiator : IMediator, serviceUrl : string) {...

Tôi sẽ đề nghị bạn thực hiện một tìm kiếm nhanh trên google về tiêm phụ thuộc . Đây không phải là diễn đàn chính xác để đặt câu hỏi này. :)
toskv

1
Tôi sẽ lấy phản hồi của bạn cho trái tim, nhưng tôi đã tìm kiếm trên google và đã gặp phải các cuộc thảo luận về tiêm phụ thuộc. Là "tiêm phụ thuộc" và "tiêm dữ liệu" đề cập đến cùng một điều? Hơn nữa, ấn tượng của tôi là "tiêm phụ thuộc" là "điều tốt" (hoặc ít nhất là "điều thay thế"), trong khi thảo luận về "tiêm dữ liệu" trong trích dẫn tôi cung cấp có vẻ như là "điều xấu" .

Phụ thuộc tiêm và tiêm dữ liệu là 2 điều khác nhau. thứ nhất là một nguyên tắc thiết kế trong khi thứ 2 là một kiểu tấn công. Nếu bạn muốn một thuật ngữ tìm kiếm rõ ràng hơn, hãy thử "đảo ngược quyền kiểm soát". Nó rộng hơn một chút nhưng cũng giúp vẽ một bức tranh rõ ràng hơn.
toskv

1
Các cuộc tấn công "tiêm dữ liệu", tôi tin rằng, là một động vật rất khác với những gì tác giả của cuốn sách được trích dẫn nói về khi ông nói "tiêm dữ liệu". Đó là một trong những lý do khiến tôi thất vọng với các tìm kiếm của Google về điều này. Ngay cả khi tôi cần hiểu, ví dụ như các nguyên tắc RẮN tốt hơn, tôi không hiểu cách cung cấp "tên" làm tham số cho hàm tạo "Người" là bình thường và OK nhưng cung cấp "serviceUrl" làm tham số cho "Mô hình" hàm tạo không phù hợp hoặc thậm chí nó khác với ví dụ "tên" / "Người".

7
Tôi nghĩ Remo đã nhầm. Thông số dữ liệu, bất kể ông nói gì. Dữ liệu được tiêm luôn có một loạitất cả các loại trong các ngôn ngữ hướng đối tượng có hành vi nào đó.
Robert Harvey

Câu trả lời:


5

Tôi sẽ cung cấp cho tác giả lợi ích của sự nghi ngờ và có lẽ đó là cách mọi thứ dành cho Bản mô tả, nhưng nếu không thì trong các môi trường khác, đó là một tuyên bố hoàn toàn không có căn cứ mà không nên thực hiện nghiêm túc.

Ngoài đỉnh đầu, tôi có thể nghĩ ra nhiều tình huống trong đó việc truyền dữ liệu qua hàm tạo là tốt, một số là trung tính, nhưng không có trường hợp nào xấu cả.

Nếu một lớp cụ thể phụ thuộc vào một phần dữ liệu cụ thể để ở trạng thái hợp lệ và chạy đúng, thì sẽ hoàn toàn hợp lý khi yêu cầu dữ liệu đó trong hàm tạo. Một lớp đại diện cho một cổng nối tiếp có thể lấy tên cổng, một đối tượng tệp có thể yêu cầu tên tệp, khung vẽ yêu cầu độ phân giải của nó, trừ khi bạn chuyển dữ liệu trong hàm tạo, có thể bạn có thể có đối tượng ở trạng thái không hợp lệ phải được theo dõi và kiểm tra Mặt khác, bạn chỉ có thể kiểm tra lúc khởi tạo đối tượng và sau đó giả sử nó hoạt động với hầu hết các phần. Các tác giả tuyên bố làm cho tình huống có lợi là không thể.

Ngoài ra, việc quyết định cấm truyền dữ liệu trong một hàm tạo cũng làm cho hầu như tất cả các đối tượng bất biến là không thể. Các đối tượng bất biến có nhiều lợi ích khác nhau trong nhiều tình huống và tất cả những điều đó sẽ bị loại bỏ với chính sách của tác giả.

Ngay cả khi các đối tượng có thể thay đổi là những gì bạn muốn, thì thực tế tồi tệ này như thế nào:

var blah = new Rectangle(x,y,width,height);

ủng hộ:

var blah = new Rectangle();
blah.X = x;
blah.Y = y;
blah.Width = width;
blah.Height = height;

Có phải tác giả thực sự nghĩ rằng đầu tiên là thực hành xấu và tôi nên luôn luôn đi với tùy chọn 2? Tôi nghĩ đó là một cuộc nói chuyện điên rồ.

Vì vậy, vì tôi không có cuốn sách và dù sao tôi cũng sẽ không đọc nó, tôi đã xem tuyên bố đó và gần như bất kỳ tuyên bố chung nào trong đó vào thời điểm này với một sự nghi ngờ đáng kể.


Cảm ơn rất nhiều cho cuộc thảo luận của bạn. Những gì bạn nói "có mùi đúng" với tôi, đặc biệt là khi bạn đưa ra ví dụ Hình chữ nhật. Tôi vẫn tự hỏi nếu tác giả đang phân biệt giữa dữ liệu cần thiết cho lớp so với từng trường hợp của lớp. Tuy nhiên, tôi không nghĩ rằng dự án mà cuốn sách mô tả thực sự đi sâu vào đủ để làm rõ điều đó. Như một lưu ý phụ, câu trả lời của bạn đã gửi cho tôi trong một cuộc điều tra ban đầu về tính bất biến của đối tượng, tuy nhiên nó không hoặc không liên quan đến câu hỏi ban đầu của tôi, vì vậy cũng cảm ơn vì điều đó!
Andrew Willems

0

Tôi nghĩ rằng nó phụ thuộc vào bối cảnh loại mô hình nào đang được thảo luận ở đây. Tôi không có sách của Remo, nhưng tôi đoán rằng mô hình đó là một loại mô hình dịch vụ, cần lấy dữ liệu từ một dịch vụ web từ xa. Nếu đó là trường hợp, là một mô hình dịch vụ web, tốt hơn là truyền tất cả dữ liệu cần thiết làm đối số trong các phương thức của dịch vụ web, làm cho dịch vụ không trạng thái.

Dịch vụ phi trạng thái có một số lợi thế, ví dụ, bất kỳ ai đọc cuộc gọi phương thức dịch vụ không cần phải tra cứu khi dịch vụ được xây dựng để tìm hiểu chi tiết về dịch vụ được gọi. Tất cả các chi tiết được hiển thị trong các đối số đang được sử dụng trong lệnh gọi phương thức (ngoại trừ url từ xa).


Có, mô hình cần lấy dữ liệu (cuối cùng từ một dịch vụ web từ xa như bạn đề xuất, nhưng trong cuốn sách này chỉ là bản demo, vì vậy ban đầu nó chỉ là giả lập dữ liệu được mã hóa trực tiếp). Tôi không hiểu đề xuất của bạn về việc truyền dữ liệu dưới dạng đối số "trong phương thức của dịch vụ web". Tôi đã hỏi về sự khác biệt giữa việc truyền dữ liệu dưới dạng tham số (1) cho hàm tạo so với (2) cho trang trí. Có vẻ như bạn đang đề xuất tùy chọn thứ 3, tức là truyền dữ liệu dưới dạng tham số / đối số cho một phương thức của dịch vụ web. Tôi có thiếu điểm của bạn không?
Andrew Willems

0

Chỉ cần đoán.

Nếu tôi nghe 'hành vi tiêm chứ không phải dữ liệu', tôi sẽ nghĩ đến, thay vì làm điều này:

(Xin lỗi vì ví dụ trong mã giả):

class NoiseMaker{
  String noise;
  NoiseMaker(String noise){
     this.noise = noise;
  }
  void soNoise(){
    writeToOutput(noise)
  }
}

Để làm điều này:

interface Noise{
  String getAudibleNoise();
}

class PanicYell implements Noise{
   String getAudibleNoise(){
       return generateRandomYell();
   }
   .....
}



class WhiteNoise implements Noise{
   String getAudibleNoise(){
       return generateNoiseAtAllFrequences();
   }
   .....
}

class NoiseMaker{
  Noise noise;
  NoiseMaker(Noise noise){
     this.noise = noise;
  }
  void soNoise(){
    writeToOutput(noise.getAudibleNoise())
  }
}

Bằng cách này, bạn có thể thay đổi hành vi của nhiễu luôn, biến nó thành ngẫu nhiên, phụ thuộc vào một biến bên trong ...

Tôi nghĩ rằng đó là tất cả về quy tắc 'ưu tiên tổng hợp hơn kế thừa'. Đó là một quy tắc tuyệt vời, tôi phải nói.

Điều này KHÔNG Ý NGH thatA rằng bạn không thể 'tiêm' tên vào Đối tượng 'Người', rõ ràng, vì tên đó hoàn toàn là dữ liệu kinh doanh. Nhưng trong ví dụ mà bạn đưa ra, dịch vụ web, URL là thứ bạn cần để tạo ra thứ gì đó kết nối một dịch vụ. Đó là một hành vi nào đó : nếu bạn tiêm URL, bạn tiêm 'dữ liệu' cần thiết để xây dựng 'hành vi', vì vậy trong trường hợp đó tốt hơn là thực hiện hành vi bên ngoài và tiêm nó sẵn sàng để sử dụng: Thay vào đó hãy tiêm URL một kết nối có thể sử dụng hoặc một kết nối có thể sử dụng.

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.