2009-06-23 17 views
21

Tôi bị buộc vào một dự án phần mềm tại nơi làm việc cách đây vài năm, và buộc phải học C# nhanh chóng. Nền lập trình của tôi yếu (ASP cổ điển).Một số ưu điểm khi sử dụng giao diện trong C#?

Tôi đã học được khá nhiều trong những năm qua, nhưng do tính chất bắt buộc của cách tôi học C#, có rất nhiều khái niệm cơ bản mà tôi chưa rõ.

Cụ thể, một giao diện. Tôi hiểu những điều cơ bản, nhưng khi viết một ứng dụng, tôi đang gặp khó khăn trong việc tìm ra cách sử dụng thực tế của một ứng dụng. Tại sao một người muốn viết một giao diện cho ứng dụng của họ?

Cảm ơn Kevin

+7

Xem tại đây http://stackoverflow.com/questions/56867/interface-vs-base-class và tại đây http://stackoverflow.com/questions/444245/how-will-i-know-when-to- tạo một giao diện và tìm kiếm "C# interface" để biết thêm. – Marc

Trả lời

16

Giao diện cho biết cách thức hoạt động. Hãy nghĩ về nó như một hợp đồng hoặc một mẫu. Nó là chìa khóa cho những thứ như Inverson của Control hoặc Dependancy Injection.

Tôi sử dụng Sơ đồ cấu trúc làm vùng chứa IoC của mình. Điều này cho phép tôi xác định một giao diện cho tất cả các lớp của tôi. Trong trường hợp bạn có thể nói

Widget w = new Widget(); 

tôi sẽ nói

IWidget w = ObjectFactory.GetInstance<IWidget>(); 

này là rất mạnh mẽ trong mã của tôi là không nói hẳn những gì một Widget thật sự là. Nó chỉ biết những gì một Widget có thể làm dựa trên giao diện của IWidget.

Điều này có một số sức mạnh tuyệt vời để nó trong đó bây giờ mà tôi đang sử dụng một container IoC tôi có thể làm một vài điều tiện lợi hơn. Trong bài kiểm tra đơn vị của tôi, nơi tôi cần phải sử dụng một Widget tôi có thể tạo ra một giả cho Widget. Vì vậy, nói rằng Widget của tôi làm một cái gì đó rất mạnh mẽ bằng cách kết nối với một cơ sở dữ liệu hoặc một dịch vụ web, mô phỏng của tôi có thể mô phỏng kết nối với các tài nguyên này và trả về cho tôi dữ liệu được phân tích. Điều này làm cho thử nghiệm của tôi chạy nhanh hơn và hoạt động theo cách đáng tin cậy hơn. Bởi vì tôi đang sử dụng StructureMap tôi có thể nói StructureMap để tải việc thực hiện thực tế của Widget của tôi trong quá trình sản xuất sử dụng mã của tôi và phiên bản giả của Widget trong quá trình thử nghiệm hoặc lập trình hoặc theo cấu hình.

Ngoài ra, vì tôi đang sử dụng vùng chứa IoC, tôi có thể cung cấp các tính năng mới thú vị cho ứng dụng của mình như viết ba cách khác nhau để lưu trữ dữ liệu. Tôi có thể có một bộ nhớ cache hộp phát triển địa phương bằng cách sử dụng một công cụ như Lucene.NET cho một bộ nhớ cache cục bộ. Tôi có thể có một máy chủ phát triển sử dụng bộ nhớ cache .NET chạy rất tốt trên một hộp. Và sau đó tôi có thể có một lựa chọn thứ ba cho các máy chủ sản xuất của tôi sử dụng một lớp bộ nhớ cache như MemCache Win32 hoặc Velocity. Miễn là tất cả ba triển khai bộ nhớ đệm đều tuân theo cùng một giao diện, việc triển khai thực tế của chúng không ảnh hưởng đến tôi (hoặc mã của tôi). Tôi chỉ đơn giản yêu cầu StructureMap đi lấy môi trường hiện tại và sau đó đi làm.

Nếu bạn theo dõi Dependency Injection thì giao diện có ích ở đây cũng với vùng chứa IoC như StructureMap trong đó tôi có thể khai báo cách sử dụng lớp bằng giao diện trong hàm tạo của lớp.

public class Widget(IWidgetRepository repository, IWidgetService service) : IWidget 
{ 
    //do something here using my repository and service 
} 

Và sau đó khi tôi mới lên một thể hiện của Widget bằng cách StructureMap như

IWidget widget = ObjectFactory.GetInstance<IWidget>(); 

Thông báo này rằng tôi không xác định kho hoặc dịch vụ trong các nhà xây dựng. StructureMap biết theo cách của các giao diện được chỉ định trong hàm dựng làm thế nào để đi lấy các cá thể thích hợp và truyền chúng vào. Điều này làm cho mã rất mạnh mẽ và sạch sẽ!

Tất cả từ định nghĩa đơn giản về Giao diện và một số cách sử dụng thông minh của chúng!

0

bài viết hay.

Giao diện là hợp đồng đảm bảo cho khách hàng cách lớp hoặc cấu trúc hoạt động như thế nào.

http://www.codeguru.com/csharp/csharp/cs_syntax/interfaces/article.php/c7563

này có thể là cách rõ ràng nhất dễ nhất để giải thích mà tôi đã đi qua:

"Câu trả lời là họ cung cấp một cách công bằng gõ an toàn phương tiện xây dựng thói quen chấp nhận đối tượng khi bạn don Điều duy nhất bạn biết về các đối tượng sẽ được chuyển đến thói quen của bạn là họ có các thành viên cụ thể phải có mặt để thói quen của bạn có thể làm việc với Ví dụ tốt nhất mà tôi có thể cung cấp cho nhu cầu giao diện là trong môi trường nhóm. ts nói chuyện với nhau. Bằng cách sử dụng giao diện, bạn loại bỏ khả năng một nhà phát triển sẽ hiểu sai những thành viên nào họ phải thêm vào một loại hoặc cách họ sẽ gọi một loại khác xác định giao diện. Nếu không có một giao diện, các lỗi sẽ leo vào hệ thống và không hiển thị cho đến khi chạy, khi chúng khó tìm. Với giao diện, sai sót trong việc xác định một loại được bắt ngay tại thời gian biên dịch, nơi chi phí là ít hơn nhiều."

7

Trường hợp cơ bản là 'IWriter' trường hợp.

Giả sử bạn đang làm cho một lớp học mà có thể viết với bàn điều khiển và nó có tất cả các chức năng hữu ích như write() và peek()

Sau đó, bạn muốn viết một lớp có thể ghi vào máy in, thay vì phát minh lại một lớp mới, bạn sử dụng

Bây giờ điều thú vị về giao diện là bạn có thể viết tất cả các mã viết của bạn, mà không biết những gì là mục tiêu viết của bạn trước, và sau đó có thể khi người dùng quyết định (thời gian chạy) thời tiết mà anh ta muốn ghi vào bàn điều khiển hoặc máy in, bạn chỉ cần xác định đối tượng dưới dạng bàn điều khiển/máy in và bạn không cần phải thay đổi bất kỳ điều gì mã viết của bạn, bởi vì cả hai đều sử dụng cùng một giao diện người dùng (giao diện).

0

Đây là một số book nói về tất cả các giao diện. Nó khuyến khích quan niệm rằng giao diện thuộc về máy khách , tức là người gọi. Đó là một khái niệm tốt đẹp. Nếu bạn chỉ cần thứ mà bạn đang gọi để thực hiện - say - count() và get(), thì bạn có thể định nghĩa một giao diện như vậy và cho phép các lớp thực hiện các hàm đó. Một số lớp sẽ có nhiều chức năng khác, nhưng bạn chỉ quan tâm đến hai hàm này - vì vậy bạn cần biết ít hơn về các lớp bạn đang làm việc. Miễn là họ thỏa mãn hợp đồng, bạn có thể sử dụng chúng.

1

Ví dụ. Xem xét một ứng dụng MDI hiển thị các báo cáo, về cơ bản có 2 loại báo cáo khác nhau. Biểu đồ và lưới. Tôi cần lưu các báo cáo này dưới dạng PDF và tôi cần gửi chúng cho ai đó. Việc xử lý sự kiện cho menu người dùng nhấp chuột để lưu lại báo cáo sang PDF có thể làm điều này:

void ExportPDF_Clicked(...) { 
    if(currentDocument is ChartReport) { 
     ChartReport r = currentDocument as ChartReport; 
     r.SavePDF(); 
    } else if(currentDocument is GridReport) { 
    GridReport r = currentDocument as GridReport; 
     r.SavePDF(); 
    } 
} 

Tôi thà sẽ làm ChartReport tôi và GridReport thực hiện giao diện này:

public interface Report { 
    void MailTo(); 
    void SavePDF(); 
} 

Bây giờ tôi có thể do:

void ExportPDF_Clicked(...) { 
    Report r = currentDocument as Report; 
    r.SavePDF(); 
} 

Tương tự như mã khác cần thực hiện thao tác tương tự (lưu vào tệp, phóng to, in, vv) trên các loại báo cáo khác nhau. Đoạn mã trên sẽ vẫn hoạt động tốt khi tôi thêm PivotTableReport cũng sẽ đẩy Rpoert vào tuần tới.

1

IOC và tiêm phụ thuộc đã được đề cập ở trên và tôi sẽ khuyên bạn nên xem xét chúng.

Tuy nhiên, phần lớn giao diện cho phép hợp đồng được chỉ định cho đối tượng không yêu cầu mô hình kế thừa.

Cho phép nói rằng tôi có lớp Foo, có hàm x và y và thuộc tính z và tôi tạo mã của mình xung quanh nó.

Nếu tôi phát hiện ra cách tốt hơn để thực hiện Foo, hoặc một loại Foo khác yêu cầu triển khai, tôi có thể mở rộng lớp Foo cơ sở thành FooA, FooB, MyFoo, v.v. cùng một chức năng cốt lõi, hoặc, thực sự là bất kỳ người sáng tạo Foo nào trong tương lai đều có quyền truy cập vào lớp Foo cơ bản và hiểu hoạt động nội bộ của nó. Trong C#, điều đó có nghĩa là các Foos tương lai không thể kế thừa từ bất kỳ thứ gì khác ngoài Foo, vì C# không hỗ trợ đa kế thừa.

Nó cũng sẽ yêu cầu tôi phải biết các trạng thái tương lai có thể có của Foo và cố gắng không để ức chế chúng trong lớp Foo cơ sở của tôi. IF2 chỉ đơn giản nói rõ 'hợp đồng' mà một lớp yêu cầu làm việc trong khuôn khổ Foo của tôi, và tôi không quan tâm những gì mà các lớp Foo tương lai có thể kế thừa hoặc trông giống như trong nội bộ, miễn là chúng có fn x fn y và z. Nó làm cho một khuôn khổ linh hoạt hơn nhiều và mở ra để bổ sung trong tương lai.

Nếu, tuy nhiên, Foo yêu cầu một lượng lớn lõi tại cơ sở của nó để hoạt động sẽ không thể áp dụng trong trường hợp hợp đồng, đó là khi bạn ưu tiên thừa kế.

6

Một đơn giản trả lời: Sử dụng giao diện cho chương trình chống lại hợp đồng chứ không phải là thực hiện.

Làm cách nào điều đó có thể hữu ích? Bắt đầu sử dụng giao diện sẽ (hy vọng) giúp bạn có thói quen kết nối các lớp học lỏng lẻo hơn. Khi bạn mã hóa với các lớp cụ thể của riêng bạn, thật dễ dàng để bắt đầu chọc các cấu trúc dữ liệu mà không có sự phân tách nghiêm ngặt các mối quan tâm. Bạn kết thúc với các lớp học mà "biết" tất cả mọi thứ về các lớp khác và mọi thứ có thể nhận được khá rối. Bằng cách giới hạn bản thân với giao diện, bạn chỉ có đảm bảo rằng nó thỏa mãn hợp đồng của giao diện. Nó tiêm một ma sát đôi khi hữu ích chống khớp nối chặt chẽ.

0

Một vài điều, khi bạn kế thừa từ một giao diện, nó buộc bạn phải thực hiện tất cả các phương thức được xác định trong giao diện. Đối với người khác, đây cũng là một cách tốt để mang lại nhiều thừa kế không được hỗ trợ cho các lớp thông thường. http://msdn.microsoft.com/en-us/library/ms173156.aspx

0

câu trả lời đơn giản dựa trên các nguyên tắc đầu tiên:

Một chương trình là một vũ trụ với siêu hình học của riêng nó (thực tế/chất/stuff của mã) và nhận thức luận (những gì bạn có thể biết/tin/Lý do về mã). Một ngôn ngữ lập trình tốt sẽ cố gắng tối đa hóa tính linh hoạt siêu hình (cho phép bạn tạo ra những thứ dễ dàng) trong khi đảm bảo sự khắt khe về thời gian (đảm bảo vũ trụ của bạn là nội bộ nhất quán). Vì vậy, hãy suy nghĩ về việc thừa kế thực hiện như một khối xây dựng siêu hình (những thứ tạo nên vũ trụ mã của bạn) và giao tiếp thừa kế như một ràng buộc sinh tồn (nó cho phép bạn tin điều gì đó về mã của bạn).

Bạn sử dụng giao diện khi bạn chỉ muốn đảm bảo rằng bạn có thể tin điều gì đó. Hầu hết thời gian đó là tất cả những gì bạn cần.

0

Bạn đã đề cập đến việc gặp khó khăn khi tìm cách sử dụng thực tế cho giao diện .. Tôi đã phát hiện ra rằng ứng dụng có thể mở rộng, ví dụ như ứng dụng dựa trên plugin, nơi plugin của bên thứ ba phải tuân thủ các quy tắc cụ thể. Những quy tắc này có thể được xác định bởi một giao diện.

Bạn có thể làm cho nó để khi các plugin được tải, nó phải có một phương pháp Init có một lớp thực hiện giao diện IServices.

public interface IServices 
{ 
    DataManager Data { get; set; } 
    LogManager Log { get; set; } 
    SomeOtherManager SomeOther { get; set; } 
} 

public class MrPlugin 
{ 
    public void Init(IServices services) 
    { 
     // Do stuff with services 
    } 
} 

Vì vậy .. Nếu bạn có một lớp mà thực hiện giao diện IServices, và sau đó bạn khởi tạo nó một lần, bạn có thể vượt qua nó để tất cả các plug-in khi khởi động và họ có thể sử dụng bất cứ dịch vụ mà bạn đã xác định trong giao diện .

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