2010-07-19 33 views
14

Những 2-3 năm qua, nhiều dự án tôi thấy, như Cuyahoga mã nguồn mở C# CMS, có xu hướng xác định các lớp học liên tục và không liên tục là Interface. Tại sao? Có lý do chính đáng nào không? TDD? Mocking? Một mẫu thiết kế? ...Tại sao các lớp học có xu hướng được định nghĩa là giao diện hiện nay?

+7

tại sao không? Nhưng chúng không định nghĩa các giao diện _as_ lớp. Họ phơi bày chúng _through_ một giao diện. –

+0

@Henk, Có. Bạn đúng rồi. –

Trả lời

22

Lý do chính là điều này làm cho các kỹ thuật như dependency injection dễ dàng hơn. Điều này lần lượt cho phép linh hoạt hơn trong phần mềm và tái sử dụng dễ dàng hơn và kết hợp lại mã hiện có. Các ví dụ về vị trí này hữu ích bao gồm các hình thức thử nghiệm đơn vị khác nhau (như bạn đã đề cập), nhưng cũng hầu hết các dạng tái sử dụng mã "thông thường" khác.

Một ví dụ đơn giản:

Giả sử bạn có một phương pháp để tính toán tiền lương emplyoee. Là một phần của chữ ký của mình, nó chấp nhận một đối tượng mà tính toán lợi ích của họ, nói một thể hiện của BenefitCalculator:

calculateSalary(... BenefitCalculator bc, ...) 

Ban đầu, thiết kế của bạn chỉ có một lớp BenefitCalculator. Nhưng sau đó, hóa ra bạn cần nhiều hơn một lớp, ví dụ: vì các phần khác nhau của phần mềm được cho là sử dụng các thuật toán khác nhau (có thể để hỗ trợ các quốc gia khác nhau hoặc vì thuật toán được cho là có thể định cấu hình người dùng ...). Trong trường hợp đó, thay vì bloat việc triển khai BenefitCalculator hiện tại, bạn nên tạo các lớp mới, ví dụ: BenefitCalculatorFrance, hoặc BenefitCalculatorSimple, vv

Bây giờ nếu bạn sử dụng chữ ký

calculateSalary(... BenefitCalculator bc, ...) 

, bạn đang loại hơi say, bởi vì bạn không thể cung cấp triển khai khác nhau. Tuy nhiên, nếu bạn sử dụng

calculateSalary (... IBenefitCalculator bc, ...)

bạn có thể chỉ có tất cả các lớp thực hiện giao diện.

Đây thực sự chỉ là trường hợp đặc biệt của "khớp nối lỏng lẻo": Nhu cầu càng ít càng tốt từ các phần khác của mã. Trong trường hợp này, không yêu cầu một lớp nhất định; thay vì chỉ yêu cầu một số phương thức tồn tại, đó chỉ là giao diện của giao diện.

+0

IIRC thuật ngữ cho điều này là [khớp nối lỏng lẻo] (http://en.wikipedia.org/wiki/Loose_coupling). –

+0

@ Chris: Vâng, đúng vậy. Xem câu trả lời của tôi (đoạn cuối) :-). – sleske

+0

Ah, tôi nhớ đọc ban đầu. –

1

Giao diện có lợi thế là chúng giúp bạn độc lập với việc triển khai, đó là điều tốt.

3

Trước hết, bạn không thể xác định lớp là giao diện. Lớp học của bạn thực hiện một giao diện.

Giao diện được sử dụng như một cách để kích hoạt hành vi đa hình. Mỗi lớp thực hiện giao diện là miễn phí để chỉ định thực hiện riêng của nó về các phương thức được định nghĩa trong giao diện. Hãy thực hiện theo các ví dụ sau:

Bạn đang viết phần mềm ngân hàng. Nhiệm vụ của bạn là viết một bộ xử lý giao dịch. Bây giờ, bạn biết bạn cần phải xử lý các loại Giao dịch khác nhau (Tiền gửi, Rút tiền, Chuyển khoản). Bạn có thể viết mã trông giống như:

public class TransactionProcessor 
{ 
    public void ProcessDeposit(// Process Deposit); 
    public void ProcessWithdraw(// Process Withdraw); 
    public void ProcessTransfer(// Process Transfer); 
} 

Và sau đó mỗi khi ai đó thêm loại Giao dịch mới, bạn phải sửa đổi lớp học của mình.Hoặc, bạn có thể:

public interface ITransaction { void Process(); } 

public class TransactionProcessor 
{ 
    public void ProccessTransaction(ITransaction t) { t.Process(); } 
} 

Bây giờ bạn không cần phải sửa đổi mã của mình để Xử lý loại giao dịch mới. Bạn chỉ cần mọi người tạo ra lớp riêng của họ thực hiện ITransaction và lớp của bạn sẽ "chỉ xử lý nó".

Điều này cho phép bạn trao đổi triển khai giao diện tùy thuộc vào nhu cầu của bạn. Nó cũng cho phép những thứ như Dependency Injection và Mocking Frameworks cho Unit Testing.

Nói chung, nó thực sự chỉ là một cách khác để làm cho mã của bạn linh hoạt hơn.

1

Trong những năm qua IoC container trở nên khá phổ biến với các nhà phát triển. Ví dụ: Unity Container từ Microsoft Practices. Vì vậy, khi bắt đầu ứng dụng, bạn có thể đăng ký các lớp cụ thể thực hiện các giao diện, và sau đó, tất cả các lớp có chứa các giao diện này trong các nhà xây dựng của chúng hoặc các thuộc tính của chúng được đánh dấu bằng thuộc tính [Dependency] sẽ được lấp đầy. Unity container của giải quyết. Nó khá hữu ích trong các ứng dụng với các phụ thuộc phức tạp, khi một giao diện có thể được thực hiện trong ba lớp khác nhau. Và tất cả những điều này không thể đạt được mà không cần sử dụng giao diện.

0

Với giao diện cấp thực sự nhàm chán cũng có thể giúp tạo bản dịch nhanh hơn.

public class A { 
    B b; 
} 

public class B { 
    public int getCount() { 
     return 10; 
    } 
} 

Trong trường hợp này mỗi lần thay đổi nội bộ để B được thực hiện, biên dịch cần phải đánh giá lại Một để xác định xem nó cần phải được biên dịch lại.

Thay vì chúng ta sử dụng giao diện:

class A { 
    IB b; 
} 

interface IB { 
    int getCount(); 
} 

class B : IB { 
    public int getCount() { 
     return 10; 
    } 
} 

Trong trường hợp này Một chỉ phụ thuộc vào IB. Không thay đổi thành B yêu cầu bất kỳ xem xét nào là A lúc biên dịch.

Ở quy mô, hiệu ứng này dựa trên đánh giá phụ thuộc ngắn mạch có thể tăng tốc đáng kể việc biên dịch các cơ sở mã lớn. Nó đặc biệt mạnh mẽ khi có nhiều lớp tùy thuộc vào một lớp đơn lẻ thay đổi rất nhiều.

Rõ ràng lợi ích thời gian biên dịch này chỉ hoạt động nếu các lớp không phụ thuộc tĩnh vào các lớp triển khai. Làm những điều sau đây hoàn toàn có thể đánh bại lợi ích này:.

class A { 
    IB b = new B(); 
} 

Đây là nơi Dependency Injection đi kèm trong container DI sẽ xây dựng một B và cung cấp cho nó để Một như một IB nên Một doesn không cần phải có sự phụ thuộc tĩnh.

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