2010-02-08 64 views
9

Tôi muốn biết việc sử dụng giao diện quan trọng. Tôi đã đọc nhiều bài viết nhưng không hiểu rõ khái niệm về giao diện.Tầm quan trọng của giao diện C#

Tôi đã viết một chương trình nhỏ. Tôi đã xác định Giao diện Itest.Class(Manager) đã triển khai Interface.Another class(Employee) chưa triển khai giao diện. Nhưng đã định nghĩa cùng một phương thức (DoSomething()) trong giao diện trong lớp (Employee). Tôi có thể gọi phương thức từ đối tượng lớp. Sau đó, tại sao tôi nên đi và thực hiện giao diện. Tôi có thể trực tiếp thực hiện phương thức trong một lớp và gọi phương thức. Tại sao tôi nên đi thêm bước thực hiện phương thức trong một giao diện và sau đó kế thừa giao diện theo lớp. Tôi biết giao diện hỗ trợ đa thừa kế, nhưng tôi không sử dụng nhiều thừa kế trong ví dụ này.

Cảm ơn mọi ý tưởng hoặc đầu vào.

public interface Itest 
{ 
    void DoSomething(); 
} 

public class Manager:Itest 
{ 
    public void DoSomething() 
    { 
     Console.WriteLine("test...."); 
    } 

} 
class Employee 
{ 
    public void DoSomething() 
    { 
     Console.WriteLine("test...."); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Manager m = new Manager(); 
     m.DoSomething(); 
     Employee e = new Employee(); 
     e.DoSomething(); 
     Console.ReadLine(); 
    } 
} 
+0

Tại sao không chọn ví dụ có nhiều thừa kế, ví dụ: một người quản lý hỗ trợ 'ITest' và' ISerializable' và 'ICloneable', vv Sau đó, bạn sẽ không nghi ngờ trả lời câu hỏi của riêng bạn! –

+0

Vì vậy, Giao diện được sử dụng về cơ bản để triển khai nhiều Thừa kế. không sử dụng khác. – Shikha

+3

Đây là bản sao gần giống với http://stackoverflow.com/questions/2151959/using-interface-variables - câu trả lời có thể trả lời câu hỏi của bạn (xem thêm các nhận xét cho câu trả lời được chấp nhận). – itowlson

Trả lời

0

Tất nhiên bạn có thể triển khai phương thức được khai báo trong giao diện mà không cần triển khai giao diện. Đặt đơn giản, giao diện chỉ cần đảm bảo bạn không quên nó (chúng sẽ cung cấp cho bạn các lỗi biên dịch nếu bất kỳ thành viên giao diện nào không được triển khai).

+0

Tương tự cũng đúng với các phương thức trừu tượng trong một lớp cơ sở trừu tượng. –

+0

Đúng vậy. Sự khác biệt là giao diện chỉ cung cấp mô tả phương thức khi lớp trừu tượng có thể có một mã thực hiện điều gì đó. – RaYell

+0

Các phương thức trừu tượng trong lớp trừu tượng (xem bình luận đầu tiên của tôi) chỉ đưa ra mô tả về phương thức, chính xác như các phương thức trong một giao diện. Khả năng duy nhất duy nhất cho các giao diện là đa thừa kế. –

10

Giao diện được sử dụng để trừu tượng (các lớp trừu tượng cũng được sử dụng cho điều này, nhưng thường chứa một số triển khai được thiết kế để sử dụng lại).

Trong C#, chúng cho phép sử dụng đa thừa kế, nghĩa là bạn có thể triển khai nhiều giao diện khác nhau trong một lớp.

Nếu bạn có nhiều triển khai khác nhau của giao diện, bạn có thể thay thế chúng cho nhau, miễn là bạn sử dụng khai báo giao diện.

Ví dụ:

IAnimal có thể được thực hiện bởi Cat và bởi Dog. Trong mã khác, bạn muốn gọi phương thức Talk được khai báo trong giao diện. Mã của bạn không phải quan tâm dù đó là đối tượng Cat hoặc đối tượng Dog. Bạn có thể thêm Duck hoặc Human và không thay đổi đoạn mã đó.

Điều này cũng hữu ích khi kiểm tra mã của bạn với các đối tượng giả, vì vậy một đối tượng đơn giản có thể được thay thế cho một đối tượng thực cho mục đích thử nghiệm.

Một số giao diện được sử dụng làm điểm đánh dấu để phản ánh có thể dễ dàng lấy chúng (ví dụ: giao diện ISerializable, đánh dấu lớp là có thể tuần tự hóa).

+0

"Giao diện được sử dụng để trừu tượng" - vì vậy là các lớp/phương thức trừu tượng, do đó tên. –

+1

Giao diện là khái niệm trừu tượng nhất tồn tại trong lập trình OO. Các lớp trừu tượng cụ thể hơn các giao diện và thường thực hiện một số giao diện. Điều quan trọng là khái niệm, không phải là một ngôn ngữ cụ thể gọi một khái niệm như thế nào. – Trap

+1

+1 để đề cập đến thử nghiệm, đó là lý do chính của tôi khi sử dụng giao diện - vì vậy tôi không cần bất kỳ dữ liệu thực nào trong cơ sở dữ liệu để thực hiện kiểm tra - tôi chỉ chạy mô hình bằng Moq (và những người khác làm như vậy với Rhino, NMock2 et al). – Fenton

14

Giao diện cho phép bạn sắp xếp sử dụng nhiều kế thừa. Trong ví dụ của bạn, nó sẽ cho phép bạn đặt một cá thể của Employee hoặc Manager vào cùng một biến, và sau đó gọi DoSomething trên biến đó, với cuộc gọi phương thức được gửi đến cá thể hiện đang được tham chiếu bởi biến đó. Ví dụ:

public interface IEmployee { 
    void DoSomething(); 
} 
// assume Manager and Employee both implement IEmployee 

IEmployee ie = new Manager(); 
ie.DoSomething(); // calls Manager.DoSomething() 
ie = new Employee(); 
ie.DoSomething(); // calls Employee.DoSomething() 

Nếu bạn không sử dụng giao diện, bạn sẽ phải làm:

object o; 

// assign Manager or Employee (or something else!) to o 

if (o is Manager) 
    ((Manager)o).DoSomething(); 
else if (o is Employee) 
    ((Employee)o).DoSomething(); 

Một giao diện định nghĩa một hợp đồng , và miễn là một ví dụ thực hiện giao diện mà bạn don 't quan tâm những gì nó thực sự là lúc chạy. Bạn có thể có cùng một lớp thực hiện nhiều giao diện, và sau đó sử dụng các cá thể của lớp đó trong tất cả các biến của các giao diện đó.Bạn không thể sử dụng tương tự cho các lớp trừu tượng, vì một lớp chỉ có thể kế thừa một lớp tại một thời điểm. Một ví dụ mà tôi đang sử dụng giao diện bây giờ là xác định một mô hình đối tượng - Tôi có giao diện cho các thuộc tính khác nhau (IHasStorage, IHasPrivileges, IHasCheezburger), sau đó các lớp đại diện cho các đối tượng cụ thể thực hiện thích hợp cho điều đó lớp tính

+0

+1 vì hỗ trợ cho MI là giá trị * duy nhất của giao diện (so với các lớp/phương thức trừu tượng). –

+4

Và, để khuếch đại, đoạn mã thứ hai của bạn * vẫn * sẽ không thực hiện công việc bởi vì nó không thể xử lý những thứ có thể làm được DoSomething không được dự đoán bởi tác giả của thường trình gọi điện. Nếu sau này tôi giới thiệu một lớp nhà thầu, cách tiếp cận dựa trên giao diện chỉ giữ trên rollin ', nhưng thường trình 'if (o là X)' phải được cập nhật để xử lý trường hợp mới. – itowlson

+0

Chủ sở hữu của lớp được khởi tạo nên lưu trữ nó làm loại có nguồn gốc cao nhất, tức là "Người quản lý m = Người quản lý mới();". Nếu không, bạn sẽ xóa tất cả các thuộc tính khác có thể quan trọng. ví dụ. nếu Trình quản lý triển khai IDisposable. Các phương pháp không sở hữu nên sử dụng loại có nguồn gốc ít nhất cần thiết. – adrianm

2

Khi bạn thêm giao diện cho người lao động hai lớp trở nên tương thích thông qua giao diện rằng:

public class Manager:Itest { ... } 

class Employee:Itest { ... } 

static void ShowSomething(Itest test) 
{ 
    test.DoSomething(); 
} 

static void Main(string[] args) 
{ 

    Manager m = new Manager();    
    Employee e = new Employee(); 

    ShowSomething(m); 
    ShowSomething(e); 
} 

Hãy nhìn vào cách các BCL sử dụng giao diện, để bắt đầu nhìn lên IDisposable, ISerializable, IComprab le và IEnumerable

1

Việc kế thừa giao diện cho bạn khả năng thay đổi việc triển khai của bạn với lớp hoặc đối tượng khác mà không vi phạm mã của bạn. Giao diện có nghĩa là bạn thực hiện một hợp đồng với các khách hàng của mã của bạn mà bạn sẽ cung cấp một số chức năng và họ không phải biết lớp học cụ thể để gọi cho điều này. Giao diện thêm một lớp trừu tượng, do đó, các khách hàng của mã của bạn sẽ không phụ thuộc vào cách triển khai giải pháp của bạn. Họ chỉ biết rằng bạn sẽ cung cấp cho họ, những gì có trong giao diện.

+0

Điều này đúng với các lớp trừu tượng - ngoại trừ với giao diện là * tệ hơn *. Nếu bạn thêm một phương thức vào một lớp trừu tượng, bạn có thể cung cấp một thực thi mặc định. Nếu bạn thử cùng một giao diện, bạn sẽ phá vỡ tất cả các thư viện thực hiện nó. –

+0

Lớp trừu tượng có các mục đích khác nhau. Để mã một số hành vi phổ biến cho hệ thống phân cấp và tránh trùng lặp mã. – anthares

1

Một loại suy rất tốt cho các giao diện được cung cấp Matthew Cochran

"Đây làm cho một dễ dàng hơn nhiều 'mã thế giới', trong đó điều hướng. Hãy tưởng tượng nếu thay vì học cách lái xe một chiếc xe và sau đó có thể lái bất kỳ chiếc xe nào, chúng tôi phải học cách lái xe mỗi chiếc xe mà chúng tôi vào. Nó sẽ thực sự không hiệu quả nếu sau khi học cách lái chiếc Ford Pinto, chúng tôi phải bắt đầu lại một lần nữa để tìm ra chiếc Mustang. Một cách hiệu quả hơn là đối phó với những chiếc xe giao diện: tay lái, tín hiệu rẽ, bàn đạp ga và phanh. Bằng cách này, không có vấn đề gì được thực hiện trên backend của giao diện, chúng tôi không thực sự quan tâm bởi vì cuối cùng nó đăng ký hợp đồng xe cơ bản và đó là cách chúng tôi sẽ đối phó với nó (thông qua giao diện) .2

Cùng với lời giải thích chung ở trên, hầu hết các mô hình Phần mềm thiết kế hiện đại, rất nhiều dựa vào giao diện như Dependendency tiêm

Hãy xem xét ví dụ sau:

Bạn có một lớp học có khả năng phát tệp phương tiện (mp3). Bạn đưa lớp đó cho bạn của bạn, người cố gắng chơi loại tệp MPEG. Nó sẽ không thể cho anh ta làm như vậy mà không làm thay đổi đáng kể cho bạn lớp.

public class MusicPlayer 
    { 
     void Play(Mp3 _mp3File){} 
    } 

xem xét việc này

Thay vì kiểu đi qua các tập tin mp3 để chơi Phương pháp gì nếu bạn vượt qua phương pháp này, một có nguồn gốc từ một giao diện của Loại MediaType.

public interface MediaType { } 

    public class Mp3 : MediaType 
    { } 

    public class MPEG : MediaType 
    { } 

và lớp:

public class MusicPlayer 
    { 
     void Play(MediaType _mediaFile){} 
    } 

Trong kịch bản này, bạn có thể lấy được một loại MediaFile và từ MediaType như MPEG và thông qua đó để Phương pháp Play và nó vui vẻ sẽ chấp nhận nó và chơi nó cho bạn (logic được cung cấp).

public class TestPlayers 
    { 
     public void PlayMedia() 
     { 
      MusicPlayer musicPlayer = new MusicPlayer(); 
      musicPlayer.Play(new Mp3()); 
      musicPlayer.Play(new MPEG()); 
     }  
    } 

Hope this helps

+0

Tất cả những điều trên đều đúng với các lớp trừu tượng. –

+0

Earwicker: Bạn có chắc chắn chúng tôi có thể làm điều trên với lớp trừu tượng.Bạn có bất kỳ ví dụ hoặc liên kết nào không? – Shikha

1

giao diện rất hữu ích trong một chút tình huống phức tạp hơn, ví dụ

(1) Bạn cần nhiều thừa kế (trong C# bạn không thể kế thừa từ 2 lớp), ví dụ: bạn có giao diện IProduct, IDisposable. Không phải mọi sản phẩm đều cần được xử lý, do đó, không có ý nghĩa khi thực hiện nó trên tất cả các sản phẩm, v.v.

(2) Khi bạn sử dụng tiêm phụ thuộc (đảo ngược kiểm soát) và khung mocking (ví dụ: RhinoMocks) cho bạn thử nghiệm đơn vị - sau đó bạn phải làm việc với các giao diện, nếu không khuôn khổ mocking của bạn sẽ không hoạt động.

+0

Nếu tôi không sử dụng MI, Giao diện không sử dụng? – Shikha

1

Bạn biết đấy, đủ hài hước để tôi chỉ nói chuyện với một trong những nhà phát triển của chúng tôi tại nơi làm việc về chủ đề này ngày hôm nay.

Cách dễ nhất để tôi giải thích giao diện và khả năng sử dụng của nó là gì, là ví dụ sau.

interface IGraphicsRenderer 
{ 
    Render(List<Triangle> triangles); 
} 

Sau đó, bạn có thể có 2 loại động cơ render, Direct3D hoặc OpenGL

class Direct3DRenderer : IGraphicsRenderer 
{ 
    public void Render(List<Triangle> triangles); 
} 

class OpenGLRenderer: IGraphicsRenderer 
{ 
    public void Render(List<Triangle> triangles); 
} 

Để hiển thị đó là tính hữu dụng, bạn có thể có một cái gì đó dọc theo dòng của

IGraphicsRenderer renderer = new Direct3DRenderer(); 
renderer.Render(foo); 

để thay đổi trình kết xuất đồ họa, tất cả những gì bạn cần làm là thay đổi khởi tạo.

IGraphicsRenderer renderer = new OpenGLRenderer(); 
1

Khi bạn có quá nhiều lớp học lái xe từ lớp Giao diện, bạn đảm bảo rằng tất cả chúng đều thực hiện Phương thức.

Sau đó, nếu thay đổi giao diện của bạn (ví dụ:

 public Interface IAnimal 
      { 
       public void Talk(); 
       public void Eat(); 
      } 

và sau đó bạn thêm một phương pháp khác

 public Interface IAnimal 
      { 
       public void Talk(); 
       public void Sleep(); 
       public void Eat(); 
      } 

sau đó bạn có thể đảm bảo được tất cả trong số họ sẽ thực hiện các phương pháp Sleep() nếu bạn. có quá nhiều lớp mà dervice từ IAnimal Inteface sau đó bạn có thể thực hiện Sleep() cho tất cả chúng.điều này giúp bạn mở rộng dễ dàng nhất có thể các lớp dẫn xuất của bạn

0

Tôi giả định y Bạn muốn một câu trả lời rất đơn giản.

Có 2 loại thừa kế:

  • LOẠI 1: Giao diện thừa kế (trong thuật ngữ đơn giản: khi bên ngoài của lớp được thừa hưởng)
  • TYPE 2: thực hiện thừa kế (khi bên trong của lớp được thừa hưởng)

Nếu bạn viết

class MyClass : Base {} 

bạn đang sử dụng cả hai loại 1 và 2. Tuy nhiên, nếu bạn thực hiện một giao diện đó là loại rõ ràng 1.

Loại 1 là để sử dụng đa hình và loại 2 là để tái sử dụng mã.

Vì vậy, mấu chốt là nếu bạn muốn sử dụng đa hình nhưng bạn

  • không muốn cung cấp bất kỳ thực hiện
  • hoặc đơn giản là không thể làm điều đó. Chủ yếu là trong trường hợp của đa kế thừa - lưu ý: C++ cho phép nó, nó sau một triết lý

giao diện dành cho bạn :)

Có công dụng khác (ví dụ như buộc thi hành một phương pháp) nhưng theo ý kiến ​​của tôi đây là điểm.

0

Giao diện dành cho thiết kế. Việc thực hiện thực tế sau những gì được định nghĩa trong thiết kế (giao diện đọc). Khái niệm về giao diện cho phép một sự linh hoạt để thiết kế một hệ thống mà không đi sâu vào các chi tiết của việc triển khai, hoặc giữ cho thiết kế có thể mở rộng bằng cách thực hiện các giao diện trong tương lai. Điều này còn được gọi là trừu tượng.

Trong khi giao diện cho phép linh hoạt tại thời điểm thiết kế, nó đặt ràng buộc tại thời điểm triển khai. Bất kỳ việc thực hiện giao diện nào cần được hoàn thành, có nghĩa là cần phải triển khai tất cả các đặc tả được xác định trong giao diện tại thời điểm triển khai. Ngoài ra sự linh hoạt khác tại thời điểm này là người ta có thể thực hiện nhiều giao diện trong một lớp.

Đây là một khái niệm rất mạnh mẽ cung cấp mức độ linh hoạt rất cao tại thời điểm thiết kế và đảm bảo rằng việc triển khai sẽ không phá vỡ thiết kế.

4

Mô hình kế thừa triển khai thực hiện mối quan hệ "IS A LOẠI", trong khi mô hình kế thừa giao diện mô hình mối quan hệ "CÓ THỂ BEHAVE LIKE". Không phải ngẫu nhiên mà nhiều tên giao diện BCL kết thúc bằng "-able", thể hiện khả năng làm điều gì đó. Để minh họa, hãy hình ảnh mã sau:

class Person 
{ 
    public string Name{get;set;} 
    public void Walk() {/*code elided*/} 
} 

class Employee : Person 
{ 
    public int Id{get;private set;} 
} 

Rõ ràng, một nhân viên "là một loại" Người. Tất cả nhân viên đều là con người, do đó tất cả họ đều có Tên và có thể Đi bộ(). Bằng mọi cách làm cho người hoặc nhân viên trừu tượng, nó không thay đổi thực tế là tất cả nhân viên đều là con người.

Bây giờ chúng ta hãy trừu tượng hơn một chút và nói về khái niệm là một chiếc xe. Điều thiết yếu tuyệt đối cho một thứ là một chiếc xe là nó phải có khả năng di chuyển và dừng lại. Bạn có thể bao gồm lái và chở hành khách nhưng tôi giữ nó rất trừu tượng.

Hãy nghĩ về một số thứ là phương tiện. Một chiếc xe, tất nhiên, nhưng làm thế nào về một người? Họ có thể di chuyển và dừng lại (và khi tôi đưa cho cháu trai và cháu gái của tôi heo con, tôi cũng mang theo hành khách!) Một chiếc ghế bành trướng? Tôi mãi mãi davrossing xung quanh văn phòng. Tôi cũng là một thủy thủ quan tâm, và sử dụng gió để tăng tốc và giảm tốc độ xe của tôi. Bạn không thể mô hình kiểu quan hệ này bằng cách sử dụng thừa kế thực hiện, bởi vì bạn có nhiều thứ khác nhau "có thể hành động như" một chiếc xe nhưng không phải thừa kế thừa kế từ cùng một lớp cơ sở.

Một pogostick (với lời xin lỗi đến các chuyên gia pogo-ers) LÀ MỘT LOẠI đồ chơi, nhưng CAN ACT LÀ một chiếc xe. Không phải tất cả đồ chơi đều là xe cộ. Một người không có mối quan hệ với một chiếc xe, khác với thực tế là nó có thể ACT như một chiếc xe.

interface IVehicle 
{ 
    void Move(); 
    void Stop(); 
} 

class Toy{} 

class PogoStick : Toy, IVehicle 
{ 
    public void Move(){ /* boing boing */} 
    public void Stop(){ /* fall over */} 
} 

class Car: IVehicle 
{ 
    public void Move(){ /* vroom vroom */} 
    public void Stop(){ /* <screeeech!> */} 
} 

class Person : IVehicle 
{ 
    public string Name{get;set;} 
    public void Walk() {/*code elided*/} 
    void IVehicle.Move() { Walk(); } 
    void IVehicle.Stop() { /*whatever!*/} 
} 

class Program 
{ 
    static void Main() 
    { 
    IVehicle[] vehicles = new IVehicle[3]; 
    vehicles[0] = new PogoStick(); 
    vehicles[1] = new Car(); 
    vehicles[2] = new Employee(); //implements IVehicle because it IS A KIND OF Person 

    vehicles.ForEach(v => v.Move()); 

    //it's worth pointing out that 
    vehicles[2].Stop(); 
    //works fine, but 
    Person p = new Person(); 
    p.Move(); 
    //won't, as I explicitly implemented the interface, meaning I can only get at the 
    //methods via a reference to the interface, not to the implementing class. 
    } 
} 

Để sử dụng ví dụ từ .NET, chuỗi trên trái đất có chung danh sách? Không nhiều, ngoại trừ việc tôi có thể "foreach" cả trong số họ:

class Demo 
{ 
    static void Main() 
    { 
    string s = "Hello!"; 
    List<Employee> payroll = new List<Employee>(); 

    for each (var item in s) 
    { 
     Console.WriteLine(item); 
    } 

    for each (var item in payroll) 
    { 
     Console.WriteLine(item); 
    } 
} 

Các lớp cơ sở chung cho chuỗi và Danh mục là đối tượng, nhưng không phải tất cả đối tượng là "foreach-thể", do đó phải là một cái gì đó khác đang diễn ra. Cụ thể là cả hai đều triển khai giao diện IEnumerable (có thể thực hiện được!)

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