2011-12-21 35 views
5

Câu hỏi này có thể đã được đăng trước đó, nhưng tôi không thể tìm thấy nó.Giao diện hoặc câu lệnh chuyển đổi, tìm đúng mẫu

Tôi đã viết loại điều này từ rất lâu, tôi ngồi xuống để viết một cái gì đó mới và chỉ cần bắt đầu gõ như thể đó là hình mẫu của riêng tôi. Một dự án đã xuất hiện gần đây và tôi thấy mình đang nhìn vào mã của riêng tôi và bắt đầu nghĩ nó trông như thế nào.

BackgroundInfoIfYouCare 

Trong thư viện cụ thể này, tôi cần gửi email cho người dùng. Cho đến nay có 13 email đóng hộp.

Mỗi email có mẫu riêng của nó (Tôi đang sử dụng trình phân tích cú pháp Razor, vì vậy các mẫu được viết bằng cshtml). Mỗi mẫu email có một Tên khóa của chuỗi. Mỗi email có truy vấn EF4 riêng để trả về mô hình dựa trên thực thể "thành viên" và tất cả dữ liệu có liên quan.

Tôi có một lớp chấp nhận một chuỗi là Khóa tên mẫu email.

Phương pháp sẽ chạy truy vấn thích hợp và lấy lại danh sách, lấy mẫu email.

Danh sách và mẫu được chuyển đến trình phân tích cú pháp để hợp nhất từng thành viên với mẫu và trả về một danh sách email.

EndOfBackgroundInfoIfYouCare 

Vì vậy, câu hỏi thực sự ... cách tốt nhất để làm điều này là gì?

Một cách là chỉ cần sử dụng một công tắc

public List<Membership> Execute(string TemplateKey) { 
switch (TemplateKey) 
     { 
      case "SomethingExpired": 
       QueryResult = new SomethingExpiredEmailQuery().ExecuteQuery(); 
       break; 
      case "SomethingExpireIn30": 
       QueryResult = new SomethingExpireIn30EmailQuery().ExecuteQuery(); 
       break; 
      case "FirstTimeLoginThanks": 
       QueryResult = new FirstTimeLoginThanksEmailQuery().ExecuteQuery(); 
       break; 
      case "SecurityTraining": 
       QueryResult = new SecurityTrainingEmailQuery().ExecuteQuery(); 
       break; 
      case ETC ETC ETC... 

}

Một cách khác là sử dụng một giao diện

IEmailQuery 
void ExecuteQuery() 

Nhưng nếu tôi sử dụng một giao diện tôi vẫn sẽ cần phải khởi tạo lớp Query. Nó không lưu mã và không làm cho mã dễ bảo trì hơn.

Với sự phản chiếu tôi có thể làm một cái gì đó như đặt tên tất cả các truy vấn Email bằng mẫu: Khóa mẫu email của SecurityTraining có tên truy vấn SecurityTrainingEmailQuery và tôi có thể sử dụng phản chiếu để khởi tạo và gọi phương thức ExecuteQuery.

Không sử dụng sự phản chiếu, không có cách nào để làm sạch dây dẫn này hơn?

Trả lời

3

Thực ra, điều này không quá có mùi với tôi. Nếu bạn không thích chuyển đổi-tuyên bố bạn có thể đi đường dẫn IEmailQuery và chỉ cần dây nó lên trong một Dictionary<string,IEmailQuery>. này có thể tiết kiệm một số dòng mã, như bạn có thể truy cập vào nó như thế:

QueryDictionary["MyKey"].ExecuteQuery(); 

Chúc mừng, Oliver

+0

Vâng, câu trả lời của Jon là tương tự, chỉ có cách nâng cao hơn sau đó tôi tôi sợ ;-) – Lindan

7

Một tùy chọn là có bản đồ Dictionary<string, Func<IEmailQuery>>. Bạn có thể xây dựng nó như thế này:

private static readonly Dictionary<string, Func<IEmailQuery>> MailQueryMap = 
    new Dictionary<string, Func<IEmailQuery>> { 
    { "SomethingExpired",() => new SomethingExpiredMailQuery() }, 
    { "SomethingExpireIn30",() => new SomethingExpireIn30EmailQuery() }, 
    // etc 
}; 

Sau đó:

public List<Membership> Execute(string templateKey) { 
    IEmailQuery query = MailQueryMap[templateKey].Invoke(); 
    var queryResult = query.ExecuteQuery(); 
    // ... 
} 

Nếu bạn có thể đảm bảo rằng bạn chỉ có bao giờ cần constructor parameterless, bạn có thể luôn luôn lưu trữ một Dictionary<string, Type> và nhanh chóng nó thông qua phản ánh - nhưng sẽ có một số phôi xấu xí, v.v.

EDIT: Tất nhiên, nếu tên của mẫu luôn tên của các loại, bạn có thể sử dụng

Type queryType = Type.GetType(namespacePrefix + "." + templateKey); 
IEmailQuery query = (IEmailQuery) Activator.CreateInstance(queryType); 
var queryResult = query.ExecuteQuery(); 

Bạn cũng có thể muốn xem xét sử dụng một enum thay vì sự kỳ diệu chuỗi hằng số.

+0

Làm thế nào thực hiện điều này theo các nguyên tắc mở/đóng cửa? Nếu tôi đọc đúng bài của Paul, anh ta muốn tránh phải thay đổi các lớp hiện có (mở rộng câu lệnh switch với các trường hợp mới). – Wivani

+0

@Wivani: Tôi không thấy bất cứ điều gì gợi ý rằng - tôi chỉ thấy rằng anh ấy muốn mã đơn giản và dễ bảo trì hơn. Trường hợp trong câu hỏi nó nói về việc tránh phải thay đổi các lớp học hiện có? –

+0

Đoán tôi đang làm 'một ass ra khỏi u và tôi' ;-) Hãy xem nếu Paul có thể xác nhận những gì tôi nghĩ rằng ông đang tìm kiếm. – Wivani

0

Tại sao không sử dụng phản chiếu như bạn đã đề xuất trong câu hỏi của mình? Tôi nghĩ rằng đó là một cách hợp lệ để làm loại công cụ này.

Một cách tiếp cận khác sẽ là sử dụng đảo ngược mẫu kiểm soát/phụ thuộc tiêm. Bạn định nghĩa một giao diện như bạn đã làm và đăng ký tất cả các triển khai cụ thể đã biết đến vùng chứa DI của bạn (điều này có thể được thực hiện bằng cách cấu hình hoặc theo mã).

Khi đăng ký, bạn cần phải thông báo cho DI chứa một số tên dịch vụ để phân biệt việc triển khai vì chúng triển khai cùng một giao diện.

YourIocContainer.Register<IEmailQuery>(typeof(SomethingExpiredMailQuery), 
             "SomethingExpiredMailQuery"); 

Khi instantiating, bạn có thể nhận việc thực hiện tương ứng bằng cách cung cấp tên dịch vụ một lần nữa:

public List<Membership> Execute(string TemplateKey) { 
    YourIocContainer.Resolve<IEmailQuery>(TemplateKey); 
+0

Khi tôi đang nghĩ đến việc đặt câu hỏi trên stackoverflow, điều đầu tiên tôi nghĩ đến là sự phản chiếu.Tốc độ không phải là một vấn đề vì vậy nó sẽ là một phương pháp hợp lệ để sử dụng. Tôi đã chỉ tò mò những giải pháp khác có thể được ra khỏi đó tôi đã không nghĩ đến. Tôi cũng thích giải pháp tiêm phụ thuộc của bạn. –

1

tôi muốn đi cho một mô hình Nhà máy, một cái gì đó giống như

class EmailQueryFactory 
{ 
    public IEmailQuery Create(String TemplateKey) 
    { 
    .... 
    } 
} 

và sau đó

//.. first get String TemplateKey 

IEmailQuery qry=EmailQueryFactory.Create(TemplateKey); 
qry.Execute(); 
+0

Tôi đã nghĩ đến việc sử dụng một nhà máy, nhưng sau đó trong nhà máy bạn kết thúc với cùng một vấn đề. Bạn cần phải nối dây mẫu được yêu cầu đến lớp Query thích hợp. –

0

Mẫu lệnh là một mẫu hoàn hảo để sử dụng cho kịch bản này. Xem http://www.codeproject.com/KB/books/DesignPatterns.aspx để thực hành C# mô tả về mẫu này. Lambdas như Jon Skeet đã mô tả là các cấu trúc lập trình mới hữu ích mà bạn có thể thấy. Xem Command Pattern : How to pass parameters to a command? để biết thêm thảo luận về cách sử dụng mẫu.

+0

Cảm ơn bạn đã đề cập đến Mẫu Lệnh. Buộc tôi đọc lại định nghĩa từ cuốn sách 4gang. Tôi tò mò mặc dù như những gì tôi sẽ đạt được bằng cách sử dụng nó. Tôi vẫn không cần phải tạo một thể hiện của người nhận để gọi lệnh? Đưa tôi trở lại danh sách các lớp và liên kết lệnh được yêu cầu với đúng lớp. –

Các vấn đề liên quan