Mặc dù câu trả lời cuối cùng là một năm trước, tôi muốn đưa ra một số nhận xét/nhận xét về chủ đề này.
Đáp Xem
Tôi đồng ý với @CarlManaster về mã hóa các tuyên bố switch
một lần để tránh tất cả các vấn đề nổi tiếng đối phó với mã trùng lặp, trong trường hợp này liên quan đến điều kiện (một số trong số họ được đề cập bởi @thkala).
Tôi không tin rằng phương pháp của @ KonradSzałwiński hoặc @AlexanderKogtenkov đề xuất phù hợp với kịch bản này vì hai lý do:
Thứ nhất, từ các vấn đề bạn đã mô tả, bạn không cần phải tự động thay đổi ánh xạ giữa tên của một hành động và thể hiện của một hành động xử lý nó.
Lưu ý các giải pháp này cho phép thực hiện điều đó (bằng cách chỉ định tên hành động cho một thể hiện hành động mới), trong khi giải pháp dựa trên chuyển mạch tĩnh thì không (ánh xạ được mã hóa cứng). Ngoài ra, bạn vẫn sẽ cần một điều kiện để kiểm tra xem một khóa đã cho có được xác định trong bảng ánh xạ hay không, nếu không phải là một hành động (phần default
của một câu lệnh chuyển đổi).
Thứ hai, trong ví dụ cụ thể này, dictionaries
thực sự ẩn triển khai câu lệnh chuyển đổi. Thậm chí nhiều hơn, có thể dễ dàng đọc/hiểu câu lệnh switch với mệnh đề mặc định hơn là phải thực thi tinh thần mã trả về đối tượng xử lý từ bảng ánh xạ, bao gồm cả việc xử lý khóa không được định nghĩa.
Có một cách bạn có thể thoát khỏi tất cả các điều kiện, trong đó có câu lệnh switch:
Loại bỏ các câu lệnh switch (sử dụng không có điều kiện ở tất cả)
Làm thế nào để tạo ra các đối tượng hành động ngay từ tên hành động?
Tôi sẽ không đọc được ngôn ngữ vì vậy câu trả lời này không nhận được mà dài, nhưng mẹo là nhận ra các lớp là các đối tượng quá.
Nếu bạn đã xác định một hệ thống phân cấp đa hình, không có ý nghĩa gì khi tham chiếu đến phân lớp cụ thể của BaseAction
: tại sao không yêu cầu trả lại đúng cá thể xử lý một hành động theo tên của nó?
Điều đó thường được thực hiện bởi cùng một tuyên bố chuyển đổi bạn đã viết (nói, một phương pháp nhà máy) ...nhưng còn về điều này:
public class BaseAction {
//I'm using this notation to write a class method
public static handlingByName(anActionName) {
subclasses = this.concreteSubclasses()
handlingClass = subclasses.detect(x => x.handlesByName(anActionName));
return new handlingClass();
}
}
Vậy, phương pháp đó là gì?
Đầu tiên, truy xuất tất cả các lớp con cụ thể về điều này (trỏ đến BaseAction
). Trong ví dụ của bạn, bạn sẽ lấy lại bộ sưu tập với ViewAction
, EditAction
và SortAction
.
Lưu ý rằng tôi đã nói các lớp con cụ thể, không phải tất cả các lớp con. Nếu hệ thống phân cấp sâu hơn, các lớp con cụ thể sẽ luôn là lớp con ở dưới cùng của cấu trúc phân cấp (lá). Đó là bởi vì họ là những người duy nhất không được trừu tượng và cung cấp thực hiện thực tế.
Thứ hai, nhận phân lớp con đầu tiên trả lời có thể xử lý hành động theo tên của nó hay không (tôi đang sử dụng ký hiệu lambda/đóng cửa). Một thi mẫu của phương pháp handlesByName
lớp cho ViewAction
sẽ trông như thế:
public static class ViewAction {
public static bool handlesByName(anActionName) {
return anActionName == 'view'
}
}
Thứ ba, chúng tôi gửi các tin nhắn mới đến lớp để xử lý các hành động, tạo ra hiệu quả một thể hiện của nó.
Tất nhiên, bạn phải xử lý trường hợp khi không có lớp con nào xử lý tác vụ theo tên của nó. Nhiều ngôn ngữ lập trình, bao gồm Smalltalk và Ruby, cho phép truyền phương thức phát hiện lambda/closure thứ hai sẽ chỉ được đánh giá nếu không có lớp con nào phù hợp với tiêu chí. Ngoài ra, bạn sẽ phải đối phó với trường hợp nhiều hơn một phân lớp xử lý hành động theo tên của nó (có thể, một trong những phương thức này đã được mã hóa theo cách sai).
Kết luận
Một ưu điểm của phương pháp này là hành động mới có thể được hỗ trợ bằng cách viết (và không thay đổi) mã hiện tại: chỉ cần tạo một lớp con mới của BaseAction
và thực hiện các phương pháp handlesByName
lớp một cách chính xác. Nó có hiệu quả hỗ trợ thêm một tính năng mới bằng cách thêm một khái niệm mới, mà không cần sửa đổi sự xâm nhập hiện tại. Rõ ràng là, nếu tính năng mới yêu cầu một phương thức đa hình mới được thêm vào hệ thống phân cấp, các thay đổi sẽ là cần thiết. Ngoài ra, bạn có thể cung cấp cho nhà phát triển bằng cách sử dụng phản hồi hệ thống của bạn: "Hành động được cung cấp không được xử lý bởi bất kỳ lớp con nào của BaseAction, vui lòng tạo một lớp con mới và triển khai phương pháp trừu tượng". Đối với tôi, thực tế là bản thân mô hình cho bạn biết điều gì sai (thay vì cố gắng thực hiện tinh thần một bảng tra cứu) thêm giá trị và hướng dẫn rõ ràng về những gì phải được thực hiện.
Có, điều này nghe có vẻ quá thiết kế. Hãy giữ một tâm trí cởi mở và nhận ra rằng liệu một giải pháp được thiết kế quá mức hay không phải làm, trong số những thứ khác, với văn hóa phát triển của ngôn ngữ lập trình cụ thể mà bạn đang sử dụng. Ví dụ, .NET guys có lẽ sẽ không sử dụng nó vì .NET không cho phép bạn coi các lớp là các đối tượng thực, trong khi mặt khác, giải pháp đó được sử dụng trong các nền văn hóa Smalltalk/Ruby.
Cuối cùng, hãy sử dụng cảm giác và sở thích chung để xác định trước nếu một kỹ thuật cụ thể thực sự giải quyết được vấn đề của bạn trước khi sử dụng. Nó là hấp dẫn có, nhưng tất cả các thương mại-off (văn hóa, thâm niên của các nhà phát triển, sức đề kháng để thay đổi, mở tâm trí, vv) nên được đánh giá.
vui lòng cung cấp thêm một số mã nếu bạn đang tìm kiếm hướng dẫn đa hình mà bạn có thể tìm thấy ở mọi nơi trên web. Vui lòng cung cấp một số ví dụ. – amirouche
Không thể thêm tất cả mã vào đây. Tôi đã cung cấp một ví dụ dưới đây (tìm Charles) – Charles
Bạn có thể thay thế các điều kiện còn lại bằng cách sử dụng api phản chiếu. Xác định thời gian chạy loại hành động cơ bản nào bạn muốn khởi tạo tùy thuộc vào chuỗi. có một giảm xuống này, chuỗi của bạn phải phù hợp với tên chính xác của hành động cơ sở của bạn. Bạn cũng có thể sử dụng một bản đồ băm để ánh xạ chuỗi với hành động cơ bản và chọn tại thời gian chạy. –