Các mẫu để truyền ngữ cảnh thông qua chuỗi phương thức


19

Đây là một quyết định thiết kế dường như xuất hiện khá nhiều: làm thế nào để vượt qua bối cảnh thông qua một phương thức không cần đến phương thức đó. Có một câu trả lời đúng hay không phụ thuộc vào bối cảnh.

Mã mẫu yêu cầu một giải pháp

// needs the dependency
function baz(session) {
  session('baz');
}

// doesn't care about the dependency
function bar() {
  baz();
}

// needs the dependency
function foo(session) {
   session('foo')
   bar();
}

// creates the dependency
function start() {
  let session = new Session();
  foo(session);
}

Phương pháp khả thi

  • tiêu đề
  • toàn cầu
  • đối tượng bối cảnh
  • vượt qua sự phụ thuộc thông qua
  • cà ri baz và chuyển nó vào thanh với sự phụ thuộc được đặt làm đối số đầu tiên
  • tiêm phụ thuộc

Ví dụ về nơi xuất hiện

Xử lý yêu cầu HTTP

Các đối tượng bối cảnh ở dạng thuộc tính yêu cầu thường được sử dụng: xem expressjs, Java Servlets hoặc .net's owin.

Ghi nhật ký

Đối với dân gian ghi nhật ký Java thường sử dụng toàn cầu / singletons. Xem các mẫu ghi nhật ký log4j / commons / java điển hình.

Giao dịch

Các chủ đề cục bộ thường được sử dụng để giữ một giao dịch hoặc phiên được liên kết với một chuỗi các lệnh gọi phương thức để tránh cần phải truyền chúng dưới dạng tham số cho tất cả các phương thức không cần chúng.


Vui lòng sử dụng một ví dụ có ý nghĩa hơn.
Tulains Córdova

Tôi đã thêm một số ví dụ về nơi nó xuất hiện.
Jamie McCrindle

3
Tôi có nghĩa là một mã ví dụ có ý nghĩa hơn.
Tulains Córdova

Câu trả lời:


11

Câu trả lời công bằng duy nhất là nó phụ thuộc vào thành ngữ lập trình của bạn. Nếu bạn đang sử dụng OO, gần như chắc chắn không chính xác để chuyển một phụ thuộc từ phương thức này sang phương pháp khác. Đó là một mùi mã trong OO. Trên thực tế, đó là một trong những vấn đề mà OO giải quyết - một đối tượng sửa chữa bối cảnh. Vì vậy, trong OO, một cách tiếp cận đúng (luôn có những cách khác) là phân phối sự phụ thuộc thông qua bộ điều khiển hoặc thuộc tính. Một nhà bình luận đề cập đến "Dependency Injection" và điều đó hoàn toàn hợp pháp, nhưng nó không thực sự cần thiết. Chỉ cần cung cấp sự phụ thuộc để nó có sẵn như là một thành viên foobaz.

Bạn đề cập đến cà ri, vì vậy tôi sẽ cho rằng lập trình chức năng không phải là vấn đề. Trong trường hợp đó, một tương đương triết học của bối cảnh đối tượng là đóng cửa. Bất kỳ cách tiếp cận nào, một lần nữa, sẽ sửa chữa sự phụ thuộc để nó có sẵn cho những người phụ thuộc hoạt động tốt. Currying là một trong những cách tiếp cận như vậy (và nó làm cho bạn có vẻ thông minh). Chỉ cần nhớ có những cách khác để đóng trên một phụ thuộc. Một số trong số họ là thanh lịch và một số trong số họ khủng khiếp.

Đừng quên lập trình theo hướng Aspect . Nó dường như đã không còn được ưa chuộng trong vài năm qua, nhưng mục tiêu chính của nó là giải quyết chính xác vấn đề mà bạn mô tả. Trong thực tế, ví dụ Aspect cổ điển là đăng nhập. Trong AOP, phần phụ thuộc được thêm tự động sau khi mã khác được viết. Người AOP gọi đây là " dệt ". Các khía cạnh phổ biến được dệt thành mã ở những nơi thích hợp. Điều này làm cho mã của bạn dễ suy nghĩ hơn và khá tuyệt, nhưng nó cũng thêm một gánh nặng thử nghiệm mới. Bạn sẽ cần một cách để xác định đồ tạo tác cuối cùng của bạn là âm thanh. AOP cũng có câu trả lời cho điều đó, vì vậy đừng cảm thấy sợ hãi.


Khẳng định rằng việc truyền tham số xung quanh trong các phương thức OO là mùi mã là một tuyên bố gây tranh cãi. Tôi cho rằng hoàn toàn ngược lại: khuyến khích trạng thái trộn và chức năng trong một lớp là một trong những sai lầm lớn nhất của mô hình OO và tránh nó bằng cách tiêm trực tiếp các phụ thuộc vào các phương thức, thay vì thông qua một hàm tạo là một dấu hiệu của một thiết kế tốt mã, cho dù OO hay không.
David Arno

3
@DavidArno Tôi khuyên bạn nên sử dụng một mô hình khác so với trạng thái đối tượng kết luận là "một trong những sai lầm lớn nhất của mô hình OO" và sau đó phá vỡ mô hình. Tôi không có gì chống lại hầu hết mọi cách tiếp cận nhưng thường không thích mã nơi tác giả đang chiến đấu với công cụ của họ. Nhà nước tư nhân là một đặc điểm khác biệt của OO. Nếu bạn tránh tính năng đó, bạn sẽ mất một phần sức mạnh của OO.
Scant Roger

1
@DavidArno Một lớp là tất cả trạng thái và không có chức năng không có cơ chế để thực thi các mối quan hệ bất biến trong trạng thái. Một lớp học như vậy hoàn toàn không phải là OO.
Kevin Krumwiede

@KevinKrumwiede, ở một mức độ nào đó, bạn đã áp dụng reducto ad absudium cho nhận xét của tôi, nhưng quan điểm của bạn vẫn được thực hiện tốt. Bất biến về trạng thái là một phần quan trọng của "chuyển từ OO". Vì vậy, tránh trộn lẫn chức năng và trạng thái phải cho phép đủ chức năng trong một đối tượng trạng thái khi cần thiết để đạt được bất biến (các trường được đóng gói được thiết lập bởi hàm tạo và được truy cập thông qua getters).
David Arno

@ScantRoger, tôi đồng ý một mô hình khác có thể được thông qua, đó là mô hình chức năng. Thật thú vị, hầu hết các ngôn ngữ "OO" hiện đại đều có danh sách các tính năng chức năng ngày càng tăng và do đó, có thể gắn bó với các ngôn ngữ đó và áp dụng mô hình chức năng mà không cần "chiến đấu với công cụ".
David Arno

10

Nếu barphụ thuộc vào baz, lần lượt yêu cầu dependency, sau đó baryêu cầu dependencyquá để sử dụng chính xác baz. Do đó, các cách tiếp cận chính xác sẽ là hoặc chuyển sự phụ thuộc thông qua như một tham số bar, hoặc cà ri bazvà chuyển nó sang bar.

Cách tiếp cận đầu tiên đơn giản hơn để thực hiện và đọc, nhưng tạo ra một khớp nối giữa barbaz. Cách tiếp cận thứ hai loại bỏ khớp nối đó, nhưng có thể dẫn đến mã ít rõ ràng hơn. Cách tiếp cận nào là tốt nhất do đó sẽ có khả năng phụ thuộc vào độ phức tạp và hành vi của cả hai chức năng. Ví dụ, nếubaz hoặc dependencycó tác dụng phụ, dễ kiểm tra có thể sẽ là một trình điều khiển lớn trong đó giải pháp được chọn.

Tôi đề nghị tất cả các tùy chọn khác mà bạn đề xuất đều là "hacky" về bản chất và có khả năng dẫn đến các vấn đề cả khi thử nghiệm và khó theo dõi các lỗi.


1
Tôi gần như hoàn toàn đồng ý. Dependency Injection có thể là một aproach không "hacky" khác.
Jonathan van de Veen

1
@JonathanvandeVeen, chắc chắn hành động truyền dependencyqua các tham số là tiêm phụ thuộc?
David Arno

2
@DavidArno Các khuôn khổ tiêm phụ thuộc không loại bỏ các loại phụ thuộc này, họ chỉ di chuyển chúng. Điều kỳ diệu là họ di chuyển chúng ra bên ngoài lớp học của bạn, đến một nơi mà việc kiểm tra là Vấn đề của Ai đó.
Kevin Krumwiede

@JonathanvandeVeen Tôi đồng ý, tiêm phụ thuộc là một giải pháp hợp lệ. Trong thực tế, đó là thứ tôi thường chọn nhất.
Jamie McCrindle

1

Nói theo triết học

Tôi đồng ý với mối quan tâm của David Arno .

Tôi đang đọc OP khi tìm kiếm giải pháp thực hiện. Tuy nhiên, câu trả lời là thay đổi thiết kế . "Mẫu"? Thiết kế OO, người ta có thể nói, tất cả về bối cảnh. Đó là một tờ giấy rộng lớn, trống rỗng có khả năng.

Đối phó với mã hiện có là một bối cảnh khác, tốt ,.



Tôi đang làm việc với 'vấn đề tương tự ngay bây giờ. Chà, tôi đang sửa hàng trăm dòng mã copy-n-paste đã được thực hiện chỉ để một giá trị có thể được đưa vào.

Mô đun hóa mã

Tôi đã vứt đi 600 dòng mã trùng lặp sau đó được cấu trúc lại để thay vì "Cuộc gọi A gọi C gọi D ..." Tôi có "Gọi A, trả lại, Gọi B, trả lại, Gọi C ...". Bây giờ chúng ta chỉ cần tiêm giá trị vào một trong những phương thức đó, giả sử phương pháp E.

Thêm một tham số mặc định cho hàm tạo. Người gọi hiện tại không thay đổi - "tùy chọn" là từ hoạt động ở đây. Nếu một đối số không được thông qua, giá trị mặc định được sử dụng. Sau đó, chỉ có 1 dòng thay đổi để chuyển biến vào cấu trúc mô đun được cấu trúc lại; và một thay đổi nhỏ trong phương pháp E để sử dụng nó.


Đóng cửa

Một chuỗi lập trình viên - "Tại sao một chương trình sẽ sử dụng một bao đóng?"

Về cơ bản, bạn đang tiêm các giá trị vào một phương thức trả về một phương thức được tùy chỉnh với các giá trị. Phương pháp tùy chỉnh đó sau đó được thực hiện.

Kỹ thuật này sẽ cho phép bạn sửa đổi một phương thức hiện có mà không thay đổi chữ ký của nó.


Cách tiếp cận này trông có vẻ kỳ lạ ...

Roger về vấn đề khớp nối tạm thời (liên kết của bạn), @Snowman. Điều quan trọng là thứ tự thực hiện được yêu cầu được gói gọn.
radarbob
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.