2009-12-16 101 views
12

Khi tôi học về các lớp trừu tượng được cho là WT (H *) !!!Lớp trừu tượng là gì?

CÂU HỎI:

  1. điểm của việc tạo ra một lớp học mà không thể được khởi tạo là gì?
  2. Tại sao mọi người lại muốn một lớp học như vậy?
  3. Tình huống trong đó lớp trừu tượng trở thành CẦN THIẾT là gì?

** nếu bạn biết những gì tôi có nghĩa là *

+2

câu trả lời ngắn, học kế thừa. – pstanton

+2

@pstanton: Đó là những gì tôi đang làm/cố gắng làm !!! :-D –

+4

@pstanton: Tôi không thấy cách nói cho OP hỏi những câu hỏi mà anh ta đã hỏi là một câu trả lời. –

Trả lời

17
  1. phổ biến nhất để phục vụ như một cơ sở lớp hoặc giao diện (một số ngôn ngữ có một interface cấu trúc riêng biệt, một số thì không) - nó không biết thi (có nghĩa là để được cung cấp bởi lớp con/triển khai các lớp học)
  2. trừu tượng và sử dụng lại
  3. khi lớp cơ sở có thể cung cấp không thực hiện mặc định có ý nghĩa cho phương pháp (nhưng cho phép các lớp con sử dụng lại phần không trừu tượng của triển khai; phương pháp không trừu tượng, v.v.)

Ví dụ:

public abstract class Stream { /* lots of code, some abstract methods */ } 

What the heck là một dòng tự? Loại loại luồng nào? một luồng vào một tệp? một mạng lưới? bộ nhớ đệm? Mỗi cách có thể có cách đọc/ghi khác nhau và không liên quan, nhưng cung cấp một API chung. Nó làm cho không có ý nghĩa để tạo chỉ một Stream, nhưng thông qua các lớp abstract, bạn có thể đang đến Stream API mà không biết các chi tiết:

Stream s = CreateStream(...); // I don't *care* what kind of stream 
s.Write(new byte[] {1,2,3,4,5}); 
s.Close(); 
+0

Nhưng bạn đã không tạo một cá thể ở đây bằng cách viết "Luồng s" ?? Tôi vẫn còn rất bối rối .. –

+0

Không, điều đó tuyên bố một biến có thể chứa một luồng. Việc tạo ra thực tế xảy ra ở đâu đó trong 'CreateStream()' - nó có thể thông qua một lời gọi đến 'new FileStream()', hoặc 'new MemoryStream', hoặc nó có thể trả về một luồng đã được tạo ra. Vấn đề là, bạn không quan tâm loại luồng đó là gì, chỉ cần đó là một luồng 'Stream', và vì vậy bạn có thể gọi các phương thức của' Stream' trên đó. –

+0

Liệu nó không gọi hàm tạo lớp cơ sở? Hoặc là không có constructor trong lớp trừu tượng? –

2

Vấn đề là phải xác định phương pháp có nguồn gốc lớp phải thực hiện, giống như một giao diện , mà còn cung cấp một số tình hình thực hiện (trong đó một giao diện không thể làm). Các lớp trừu tượng không bao giờ, nói đúng, "cần thiết" - nhưng chúng hữu ích. Chỉ cần tìm kiếm thư viện chuẩn .NET hoặc Java cho chúng và tự xem chúng được sử dụng như thế nào. Bạn sẽ tìm thấy có rất nhiều ví dụ.

2

Các lớp trừu tượng là chỉ hữu ích nếu bạn sử dụng thừa kế. Bạn tạo các lớp con phải thực hiện cùng một giao diện làm lớp trừu tượng của bạn và sẽ kế thừa một số triển khai cơ sở mà bạn có thể đã xác định trong lớp trừu tượng của mình.

7

Lớp Tóm tắt (Cơ sở) cung cấp cho bạn các lớp bán bê tông để triển khai phân cấp lớp của bạn.Chúng cho phép bạn làm một vài điều:

  1. Củng cố hành vi phổ biến (không giống như một giao diện mà chỉ xác định hợp đồng)
  2. Cung cấp mặc định (và tùy chọn ghi đè-thể) triển khai cho các chức năng
  3. Cung cấp điểm chi nhánh được xác định rõ cho các phân cấp thừa kế
  4. Điều khiển các điểm chèn IoC

Danh sách này tiếp tục.

+0

Điểm tiêm IoC là gì? –

+0

Đảo ngược kiểm soát. Nó là một điểm trong cấu trúc lớp của bạn, nơi bạn có ý định tiêm các hành vi cụ thể được định nghĩa rõ ràng tại thời gian biên dịch nhưng không được xác định cụ thể cho đến khi chạy. Spring là một ví dụ về triển khai IoC. – GrayWizardx

+1

Đảo ngược điều khiển - thuật ngữ cho rằng mã _you_ viết không làm tất cả công việc, nhưng điều gì đó "kỳ diệu" xảy ra ngoài tầm kiểm soát của bạn. Các đối tượng xuất hiện từ "hư không" và được gán cho các biến của bạn hoặc được truyền làm tham số cho các hàm tạo. Điều này hóa ra rất tiện dụng để tránh mã của bạn khi biết nó đang chạy bên trong một thùng chứa web và nó cần gọi FooBar để có được một kết nối cơ sở dữ liệu. –

1

Lớp trừu tượng là trừu tượng. Nó đảm bảo hành vi tồn tại nhưng không ép buộc hành vi được thực hiện như thế nào. Điều này khiến bạn tự do thay đổi cách hành vi được thực hiện, nếu sau đó bạn quyết định bạn muốn.

Sự trừu tượng giống như bàn phím, màn hình hoặc điện thoại di động. Tất cả bàn phím đều có khả năng nhập dữ liệu; tất cả các màn hình đều có khả năng hiển thị pixel; và tất cả điện thoại di động đều có khả năng thực hiện cuộc gọi. Nhưng các nhà sản xuất các mặt hàng này có những cách khác nhau để thực hiện hành vi. Vì vậy, khi bạn muốn thực hiện cuộc gọi, bạn có thể làm điều đó từ bất kỳ điện thoại di động nào vì tất cả các nhà sản xuất điện thoại di động tạo ra điện thoại tuân theo ý tưởng trừu tượng chung về điện thoại di động là gì ?. Bạn không cần phải học lại cách thực hiện cuộc gọi trên Samsung nếu bạn đã học cách thực hiện cuộc gọi trên BlackBerry hoặc LG.

Điện thoại di động là điện thoại di động và các lớp con của lớp trừu tượng là tất cả lớp trừu tượng.

+0

Trong .NET parlance ít nhất, điều này mô tả một giao diện, không phải là một lớp trừu tượng. –

5

1) Điểm tạo một lớp có thể được khởi tạo là gì?

Chỉ vì một cái gì đó không được khởi tạo trực tiếp không có nghĩa là nó hữu ích. Một lớp trừu tượng đóng một vai trò quan trọng trong kế thừa và có thể rất hữu ích trong thiết kế lớp của các lớp kế thừa của nó.

Ví dụ, tôi đã sử dụng các lớp trừu tượng trước để xác định cấu trúc cơ bản của những gì lớp học phải tuân theo. Sau đó, tôi đã định nghĩa các lớp kế thừa dựa trên lớp trừu tượng đó và nếu tôi đã bỏ lỡ một phương thức được yêu cầu hoặc một cái gì đó, nó có thể được trình biên dịch lấy ra.

Điều này cũng cho phép bạn làm là liên kết các lớp kế thừa với nhau, nghĩa là bạn có thể giả định các phương thức nhất định được xác định trong lớp trừu tượng sẽ tồn tại trong các lớp được thừa hưởng - có thể hữu ích.

2) Tại sao ai muốn như vậy một lớp

Thông thường tôi sử dụng nó để đảm bảo rằng một loạt các lớp kế thừa có phương pháp nhất định vv Đối với tôi nó là thực sự hữu ích cho thiết kế của một cấu trúc của một tập các lớp thừa kế.

3) Tình huống trong đó lớp trừu tượng trở nên cần thiết là gì?

Tôi không nghĩ lớp trừu tượng là cần thiết, nhưng khi được sử dụng trong một số trường hợp, nó có thể hữu ích và giúp đơn giản hóa vấn đề bạn đang giải quyết.

0

OK, bây giờ bạn đã tạo một giao diện với tất cả các phương pháp thay đổi trong mỗi lần triển khai. Khi bạn lập trình, bạn nhận thấy rằng một số khối mã được chia sẻ bởi TẤT CẢ các triển khai của giao diện.

Các khối mã này phải nằm trong lớp trừu tượng, thay vì được lặp lại trong mỗi lần triển khai. Bằng cách đó, khi một cái gì đó thay đổi, bạn chỉ sửa mã trong lớp trừu tượng thay vì trong mỗi lần thực hiện.

Nó chỉ trừu tượng vì bạn muốn tất cả các lớp kế thừa có triển khai riêng của chúng.

1

Lớp trừu tượng là lớp trừu tượng không thể được khởi tạo. Ví dụ, một hình vuông, hình tròn, hoặc hình chữ nhật là một loại hình dạng và có thể được bắt nguồn từ một hình dạng lớp.

Hình dạng sẽ chứa mã phổ biến cho hình vuông, hình tròn hoặc hình chữ nhật như tính diện tích của hình dạng. Nhưng instantiating một Shape sẽ là vô dụng vì nó là một khái niệm trừu tượng và hình vuông, hình tròn và hình chữ nhật là các thực thể thực.

1

Điểm của lớp trừu tượng là xác định (hạn chế) giao diện của bạn mà không mô tả triển khai.

  1. Một lớp trừu tượng có thể được khởi tạo bằng cách xây dựng một đối tượng tương thích với loại lớp dẫn xuất.

  2. Để triển khai giao diện rõ ràng ẩn mã nền tảng xấu xí. Ngoài ra để ẩn các cá nhân từ bất kỳ loại tiếp xúc nào. (Vì vậy, bạn thực sự buộc phải sử dụng lớp học với giao diện trừu tượng.)

  3. Điều này là cần thiết khi bạn có hai triển khai khác nhau của cùng một lớp hoàn toàn khác nhau. Hãy nghĩ về một tập tin, một ổ cắm và một khối bộ nhớ. Tất cả chúng có thể làm cho dữ liệu có thể đọc được - sử dụng một lớp trừu tượng, bạn có thể thực hiện ba cách đó theo ba cách khác nhau, mặc dù mã sử dụng (các trang gọi) được viết một cách để hỗ trợ cả ba.

0

Lớp trừu tượng phục vụ mục đích hữu ích bằng cách tạo ra một lớp thể hiện một khái niệm thay vì khái niệm cụ thể. Ví dụ, Animal có thể là một lớp, nhưng không ai chỉ là một con vật, nó là một trong hai một Bird, Chó, hoặc Cát vv mà nhiều loại khác nhau của động vật. Hi vọng điêu nay co ich. Nó cũng đi cùng với các khái niệm như thừa kế và đa hình.

2

Chỉ đơn giản là Ẩn cài đặt thực tế từ khách hàng sử dụng nó.

  • Nó Cung cấp thực hiện concerete cho các chức năng nhất định và điều này không thể trực tiếp instantiated
  • này sẽ chỉ được truy cập từ các lớp những người đang thực hiện điều đó.
  • Vì vậy, các khách hàng tiêu thụ lớp dẫn xuất, sẽ không bao giờ biết việc triển khai chức năng này vì nó đã được khai thác.

Bây giờ bạn sẽ hỏi tại sao chúng ta cần điều này, vì các giao diện phục vụ cùng một cơ chế.Đi qua các ví dụ logger đơn giản

interface ILogger 
{ 
    string PrepareLog(System.Exception ex); 
    void InitializeLogger(string Type); 
    int WriteLog(string msg); 
} 

Bất kỳ khách hàng khai thác gỗ thực hiện giao diện này nên thực hiện tất cả điều này chức năng

class EventLogger : ILogger 
{ 
    public override void InitializeLogger(string Type) 
    { 
     //Event Logger Initialize 
    } 
    public override int WriteLog(string msg) 
    { 
     //Write to event log 
     return 1; 
    } 
    public override string PrepareLog(System.Exception ex) 
    { 
     return ex.StackTrace ; 
    } 
} 

class FileLogger : ILogger 
{ 
    public override void InitializeLogger(string Type) 
    { 

    } 
    public override int WriteLog(string msg) 
    { 
     //Write to File 
     return 1; 
    } 
    public override string PrepareLog(System.Exception ex) 
    { 
     return ex.StackTrace ; 
    } 
} 


class MailLogger : ILogger 
{ 
    public override void InitializeLogger(string Type) 
    { 

    } 
    public override int WriteLog(string msg) 
    { 
     //Write to mail 
     return 1; 
    } 

    public override string PrepareLog(System.Exception ex) 
    { 
     //prepare HTML Formatted msg 
     return ex.StackTrace ; 
    } 
} 

Và các lớp EventLogger, FileLogger và maillogger thực hiện các iLogger và cung cấp cho các Bối cảnh cụ thể thực hiện . Bây giờ chúng tôi muốn ẩn thực hiện thực tế của PrepareLog và điều này sẽ làm các hoạt động phổ biến của chuẩn bị thông điệp tường trình từ đối tượng ngoại lệ.

Trong triển khai hiện tại của chúng tôi, chúng tôi không có tùy chọn để làm cho bê tông phương pháp đơn lẻ và các phương thức khác chỉ là hợp đồng.

để cho phép thay đổi chút thực hiện với lớp trừu tượng

abstract class AbstractLogger:ILogger 
{ 
    #region ILogger Members 

    public virtual string PrepareLog(System.Exception ex) 
    { 
     return ex.StackTrace; 
    } 

    public abstract void InitializeLogger(string Type); 
    public abstract int WriteLog(string msg); 

    #endregion 
} 


class EventLogger : AbstractLogger 
{ 
    public override void InitializeLogger(string Type) 
    { 
     //Event Logger Initialize 
    } 
    public override int WriteLog(string msg) 
    { 
     //Write to event log 
     return 1; 
    } 
} 

class FileLogger : AbstractLogger 
{ 
    public override void InitializeLogger(string Type) 
    { 

    } 
    public override int WriteLog(string msg) 
    { 
     //Write to File 
     return 1; 
    } 
} 

class DBLogger : AbstractLogger 
{ 
    public override void InitializeLogger(string Type) 
    { 

    } 
    public override int WriteLog(string msg) 
    { 
     //Write to DB 
     return 1; 
    } 
} 

class MailLogger : AbstractLogger 
{ 
    public override void InitializeLogger(string Type) 
    { 

    } 
    public override int WriteLog(string msg) 
    { 
     //Write to mail 
     return 1; 
    } 

    public override string PrepareLog(System.Exception ex) 
    { 
     //prepare HTML Formatted msg 
     return ex.StackTrace ; 
    } 
} 

Bây giờ tôi đã tạo ra lớp AbstractLogger mà thừa hưởng từ iLogger và thực hiện các phương pháp PrepareLog một mình, phương pháp remainig trái trừu tượng. vì vậy người tiêu dùng sẽ viết mã theo ngữ cảnh cụ thể trong quá trình thực hiện của họ.

Vì vậy, bây giờ phương pháp PrepareLog hoàn toàn ẩn (có nghĩa là chuẩn bị nhật ký) từ các cosumers đã khởi tạo bất kỳ Logger nào.

thì tại sao PrepareLog là Virtual ed ??

Có các tình huống mà người tiêu dùng có thể muốn ghi đè lên phương thức chuẩn bị, Ex: MailLogger sẽ ghi đè đầu ra định dạng HTML chuẩn bị và chuẩn bị để cung cấp thư.

1

Cả hai giao diện và lớp trừu tượng đều thúc đẩy khớp nối lỏng lẻo trong cơ sở mã của bạn. Các lớp trừu tượng là sự thỏa hiệp giữa các giao diện và các lớp cụ thể, bởi vì các lớp trừu tượng có thể có các phương thức thực tế với hành vi được thực hiện.

Nói chung, bạn thích giao diện. Các lớp trừu tượng rất hữu ích khi bạn có một cây thừa kế có các hoạt động chung được sử dụng bởi các lớp con. Nhưng ngay cả ở đây bạn có thể muốn khai báo rằng lớp trừu tượng của bạn thực hiện một giao diện. Josh Bloch gọi đây là mẫu "Giao diện trừu tượng". Điều này cho phép bạn triển khai các triển khai khác nhau của cả lớp trừu tượng, mà nghịch lý không thực sự là hoàn toàn trừu tượng - chỉ có các giao diện.

0

Tương tự như với các giao diện, một lớp trừu tượng là một hợp đồng mà bạn đã cung cấp một số chung (hoặc trừu tượng) chức năng đó là áp dụng đối với nhiều kịch bản, nhưng mong đợi một người thực hiện để cung cấp một số chức năng mà là cụ thể và/hoặc khác nhau cho từng kịch bản. Ai đó đã đề cập đến ví dụ Stream - ví dụ rất hay.

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