Vai trò của singletons, lớp trừu tượng và giao diện là gì?


13

Tôi đang nghiên cứu OOP trong C ++ và, mặc dù tôi nhận thức được các định nghĩa của 3 khái niệm này, tôi không thể thực sự nhận ra khi nào hoặc làm thế nào để sử dụng nó.

Hãy sử dụng lớp này cho ví dụ:

class Person{
    private:
             string name;
             int age;
    public:
             Person(string p1, int p2){this->name=p1; this->age=p2;}
             ~Person(){}

             void set_name (string parameter){this->name=parameter;}                 
             void set_age (int parameter){this->age=parameter;}

             string get_name (){return this->name;}
             int get_age (){return this->age;}

             };

1. Đơn

Làm thế nào để hạn chế của lớp chỉ có một đối tượng hoạt động?

CÓ THỂ bạn thiết kế một lớp mà có thể có CHỈ 2 trường hợp? Hoặc có thể 3?

KHI NÀO đang sử dụng một singleton được đề nghị / cần thiết? Có phải là thực hành tốt?

2. Lớp trừu tượng

Theo tôi biết, nếu chỉ có một hàm ảo thuần túy, lớp sẽ trở nên trừu tượng. Vì vậy, thêm

virtual void print ()=0;

sẽ làm điều đó, phải không?

TẠI SAO bạn sẽ cần một lớp mà đối tượng không bắt buộc?

3. Giao diện

Nếu một giao diện là một lớp trừu tượng trong đó tất cả các phương thức là các hàm ảo thuần túy, thì

Sự khác biệt chính giữa 2 người họ là gì?

Cảm ơn trước!


2
Singleton đang gây tranh cãi, hãy tìm kiếm nó trên trang web này để có nhiều ý kiến ​​khác nhau.
Winston Ewert

2
Cũng đáng lưu ý rằng trong khi các lớp trừu tượng là một phần của ngôn ngữ, thì cả singletons hay giao diện đều không. Chúng là những mẫu mà mọi người thực hiện. Singleton nói riêng là một cái gì đó đòi hỏi một chút hack thông minh để làm cho công việc. (Mặc dù tất nhiên bạn chỉ có thể tạo một singleton theo quy ước.)
Gort the Robot

1
Một tại một thời gian, xin vui lòng.
JeffO

Câu trả lời:


17

1. Đơn

Bạn hạn chế số lượng phiên bản vì hàm tạo sẽ có nghĩa là riêng tư, chỉ các phương thức tĩnh mới có thể tạo các thể hiện của lớp đó (có những thủ thuật bẩn khác thực sự để thực hiện điều đó nhưng chúng ta không được mang đi).

Tạo một lớp sẽ chỉ có 2 hoặc 3 trường hợp là hoàn toàn khả thi. Bạn nên sử dụng singleton bất cứ khi nào bạn cảm thấy cần thiết chỉ có một phiên bản của lớp đó trong toàn bộ hệ thống. Điều đó thường xảy ra với các lớp có hành vi 'người quản lý'.

Nếu bạn muốn tìm hiểu thêm về Singletons, bạn có thể bắt đầu trên Wikipedia và đặc biệt là C ++ trong bài đăng này .

Chắc chắn có một số điều tốt và xấu về mô hình này nhưng cuộc thảo luận này thuộc về một nơi khác.

2. Các lớp học trừu tượng

Vâng đúng vậy. Chỉ một phương thức ảo duy nhất sẽ đánh dấu lớp là trừu tượng.

Bạn sẽ sử dụng các loại lớp đó khi bạn có một hệ thống phân cấp lớp lớn hơn trong đó các lớp hàng đầu không thực sự được khởi tạo.

Giả sử bạn đang xác định một lớp Động vật có vú và sau đó kế thừa nó cho Chó và Mèo. Nếu bạn nghĩ về nó, sẽ không có nhiều ý nghĩa để có một ví dụ thuần túy của Động vật có vú vì trước tiên bạn cần phải biết nó thực sự là loại động vật có vú nào.

Có khả năng có một phương pháp gọi là MakeSound () sẽ chỉ có ý nghĩa trong các lớp kế thừa nhưng không có âm thanh chung mà tất cả các động vật có vú có thể tạo ra (Đó chỉ là một ví dụ không cố gắng tạo ra âm thanh cho động vật có vú ở đây).

Vì vậy, điều đó có nghĩa là Động vật có vú nên là một lớp trừu tượng vì nó sẽ có một số hành vi phổ biến được thực hiện cho tất cả các động vật có vú nhưng nó không thực sự được coi là tức thời. Đó là khái niệm cơ bản đằng sau các lớp trừu tượng nhưng chắc chắn có nhiều thứ mà bạn nên học.

3. Giao diện

Không có giao diện thuần túy trong C ++ theo nghĩa tương tự như bạn có trong Java hoặc C #. Cách duy nhất để tạo một cái là có một lớp trừu tượng thuần túy bắt chước hầu hết các hành vi bạn muốn từ một giao diện.

Về cơ bản hành vi bạn đang tìm kiếm là xác định hợp đồng nơi các đối tượng khác có thể tương tác mà không cần quan tâm đến việc triển khai cơ bản. Khi bạn tạo một lớp hoàn toàn trừu tượng, điều đó có nghĩa là tất cả việc thực hiện thuộc về một nơi khác vì vậy mục đích của lớp đó chỉ là về hợp đồng mà nó định nghĩa. Đây là một khái niệm rất mạnh mẽ trong OO và bạn chắc chắn nên xem xét nhiều hơn về nó.

Bạn có thể đọc về đặc tả giao diện cho C # trong MSDN để có ý tưởng tốt hơn:

http://msdn.microsoft.com/en-us/l Library / ms173156.aspx

C ++ sẽ cung cấp loại hành vi tương tự bằng cách có một lớp trừu tượng thuần túy.


2
Một lớp cơ sở trừu tượng thuần túy cung cấp cho bạn mọi thứ mà một giao diện thực hiện. Các giao diện tồn tại trong Java (và C #) vì các nhà thiết kế ngôn ngữ muốn ngăn chặn nhiều kế thừa (vì những vấn đề đau đầu mà nó tạo ra) nhưng đã nhận ra một cách sử dụng rất phổ biến của nhiều kế thừa không có vấn đề.
Gort Robot

@StevenBurnap: Nhưng không phải trong C ++, đó là bối cảnh của câu hỏi.
DeadMG

3
Anh ấy hỏi về C ++ và giao diện. "Giao diện" không phải là một tính năng ngôn ngữ của C ++, nhưng mọi người chắc chắn tạo ra các giao diện trong C ++ hoạt động chính xác như các giao diện Java, sử dụng các lớp cơ sở trừu tượng. Họ đã làm như vậy trước khi Java tồn tại.
Gort Robot


1
Điều tương tự cũng đúng với Singletons. Trong C ++, cả hai đều là các mẫu thiết kế, không phải là các tính năng ngôn ngữ. Điều này không có nghĩa là mọi người không nói về giao diện trong C ++ và mục đích của chúng là gì. Khái niệm "giao diện" xuất phát từ các hệ thống thành phần như Corba và COM, cả hai ban đầu được phát triển để sử dụng trong C. Trong C ++, các giao diện thường được triển khai với các lớp cơ sở trừu tượng trong đó tất cả các phương thức là ảo. Chức năng của nó giống hệt với giao diện Java. Như vậy, khái niệm giao diện Java cố ý là một tập hợp con của các lớp trừu tượng C ++.
Gort Robot

8

Hầu hết mọi người đã giải thích các singletons / lớp trừu tượng là gì. Hy vọng, tôi sẽ cung cấp một chút quan điểm khác biệt và đưa ra một số ví dụ thực tế.

Singletons - Khi bạn muốn tất cả mã gọi sử dụng một trường hợp biến duy nhất, vì bất kỳ lý do gì, bạn có các tùy chọn sau:

  • Biến toàn cục - rõ ràng là không đóng gói, hầu hết các mã được ghép với toàn cục ... xấu
  • Một lớp có tất cả các hàm tĩnh - tốt hơn một chút so với các khối đơn giản, nhưng quyết định thiết kế này vẫn đưa bạn đến một con đường nơi mã dựa trên dữ liệu toàn cầu và có thể rất khó thay đổi sau này. Ngoài ra, bạn không thể tận dụng những thứ OO như đa hình nếu tất cả những gì bạn có là các hàm tĩnh
  • Singleton - Mặc dù chỉ có một phiên bản của lớp, việc triển khai thực tế của lớp không cần phải biết gì về thực tế là nó là toàn cầu. Vì vậy, hôm nay bạn có thể có một lớp là một singleton, ngày mai bạn có thể đơn giản làm cho công cụ xây dựng của nó công khai và cho phép khách hàng khởi tạo nhiều bản sao. Hầu hết các mã khách hàng tham chiếu đến singleton sẽ không phải thay đổi và việc thực hiện chính singleton sẽ không phải thay đổi. Thay đổi duy nhất là làm thế nào mã khách hàng có được tham chiếu singleton ở vị trí đầu tiên.

Trong tất cả các lựa chọn xấu và xấu ngoài kia, nếu bạn có nhu cầu về dữ liệu toàn cầu, singleton là một cách tiếp cận tốt hơn nhiều so với một trong hai cách trước. Nó cũng cho phép bạn giữ các tùy chọn của mình mở nếu ngày mai bạn thay đổi quyết định và quyết định sử dụng đảo ngược quyền kiểm soát thay vì có dữ liệu toàn cầu.

Vì vậy, nơi bạn sẽ sử dụng một singleton? Dưới đây là một vài ví dụ:

  • Ghi nhật ký - nếu bạn muốn toàn bộ quá trình của mình có một bản ghi, bạn có thể tạo một đối tượng nhật ký và chuyển nó đi khắp nơi. Nhưng nếu bạn có 100.000k dòng mã ứng dụng cũ thì sao? sửa đổi tất cả chúng? Hoặc bạn có thể chỉ cần giới thiệu những điều sau đây và bắt đầu sử dụng nó ở bất cứ đâu bạn muốn:

    CLog::GetInstance().write( "my log message goes here" );
  • Bộ đệm kết nối máy chủ - Đây là thứ tôi phải giới thiệu trong ứng dụng của chúng tôi. Cơ sở mã của chúng tôi, và có rất nhiều, được sử dụng để kết nối với máy chủ bất cứ khi nào nó hài lòng. Hầu hết thời gian điều này là ổn, trừ khi có bất kỳ loại độ trễ nào trong mạng. Chúng tôi cần một giải pháp và thiết kế lại ứng dụng 10 năm tuổi không thực sự nằm trên bàn. Tôi đã viết một CServerConnectionManager đơn lẻ. Sau đó, tôi đã tìm kiếm thông qua mã và thay thế các cuộc gọi CoCreateInstanceWithAuth bằng cuộc gọi chữ ký giống hệt nhau đã gọi lớp của tôi. Bây giờ sau khi kết nối lần thử đầu tiên được lưu vào bộ nhớ cache và phần còn lại của thời gian "kết nối" là ngay lập tức. Một số người nói singletons là ác. Tôi nói họ đã cứu mông tôi.

  • Để gỡ lỗi, chúng ta thường thấy bảng đối tượng chạy toàn cầu rất hữu ích. Chúng tôi có một số lớp chúng tôi muốn theo dõi. Tất cả đều xuất phát từ cùng một lớp cơ sở. Trong thời gian khởi tạo, họ gọi bảng đối tượng singleton và tự đăng ký. Khi chúng bị phá hủy, chúng hủy đăng ký. Tôi có thể đi đến bất kỳ máy nào, đính kèm vào một quy trình và tạo một danh sách các đối tượng đang chạy. Đã ở trong sản phẩm hơn nửa thập kỷ và tôi chưa bao giờ cảm thấy rằng chúng tôi từng có nhu cầu về 2 bảng đối tượng "toàn cầu".

  • Chúng tôi có một số lớp tiện ích trình phân tích chuỗi tương đối phức tạp dựa trên các biểu thức thông thường. Các lớp biểu thức chính quy cần được khởi tạo trước khi nó có thể thực hiện khớp. Việc khởi tạo hơi tốn kém vì đó là khi một FSM được tạo dựa trên chuỗi phân tích cú pháp. Tuy nhiên, sau đó, lớp biểu thức chính quy có thể được truy cập an toàn bởi 100 luồng vì một khi FSM được xây dựng không bao giờ thay đổi. Các lớp trình phân tích cú pháp bên trong sử dụng singletons để đảm bảo việc khởi tạo này chỉ xảy ra một lần. Điều này cải thiện đáng kể hiệu suất và không bao giờ gây ra bất kỳ vấn đề nào do "những kẻ độc thân".

Đã nói tất cả những điều này, bạn cần phải ghi nhớ khi nào và ở đâu để sử dụng singletons. 9 trên 10 lần có một giải pháp tốt hơn và bằng mọi cách, bạn nên sử dụng giải pháp đó thay thế. Tuy nhiên, có những lúc singleton hoàn toàn là sự lựa chọn thiết kế phù hợp.

Chủ đề tiếp theo ... giao diện và các lớp trừu tượng. Đầu tiên như những người khác đã đề cập, giao diện là một lớp trừu tượng nhưng nó vượt xa điều đó bằng cách thực thi rằng nó hoàn toàn KHÔNG thực hiện. Trong một số ngôn ngữ giao diện từ khóa là một phần của ngôn ngữ. Trong C ++, chúng ta chỉ cần sử dụng các lớp trừu tượng. Microsoft VC ++ đã thực hiện một bước để xác định nội dung này ở đâu đó trong nội bộ:

typedef struct interface;

... vì vậy bạn vẫn có thể sử dụng từ khóa giao diện (thậm chí nó sẽ được đánh dấu là từ khóa 'thực'), nhưng theo như trình biên dịch thực tế có liên quan, thì đó chỉ là một cấu trúc.

Vậy bạn sẽ sử dụng cái này ở đâu? Hãy quay trở lại ví dụ của tôi về bảng đối tượng đang chạy. Giả sử lớp cơ sở có ...

in trống ảo () = 0;

Có lớp trừu tượng của bạn. Các lớp sử dụng bảng đối tượng thời gian chạy tất cả sẽ xuất phát từ cùng một lớp cơ sở. Lớp cơ sở chứa mã chung để đăng ký / hủy đăng ký. Nhưng nó sẽ không bao giờ được khởi tạo bởi chính nó. Bây giờ tôi có thể có các lớp dẫn xuất (ví dụ: yêu cầu, người nghe, đối tượng kết nối máy khách ...), mỗi lớp sẽ triển khai print () để khi gắn vào quy trình và hỏi nó, cái gì đang chạy, mỗi đối tượng sẽ báo cáo trạng thái riêng của nó.

Ví dụ về các lớp / giao diện trừu tượng là vô số và bạn chắc chắn sử dụng (hoặc nên sử dụng) chúng nhiều, thường xuyên hơn nhiều mà bạn sẽ sử dụng singletons. Nói tóm lại, chúng cho phép bạn viết mã hoạt động với các loại cơ sở và không bị ràng buộc với việc triển khai thực tế. Điều này cho phép bạn sửa đổi triển khai sau này mà không phải thay đổi quá nhiều mã.

Đây là một ví dụ khác. Hãy nói rằng tôi có một lớp thực hiện một logger, CLog. Lớp này ghi vào tệp trên đĩa cục bộ. Tôi bắt đầu sử dụng lớp này trong 100.000 dòng mã kế thừa của mình. Khắp nơi. Cuộc sống là tốt cho đến khi ai đó nói, hey hãy viết vào cơ sở dữ liệu thay vì một tập tin. Bây giờ tôi tạo lớp mới, hãy gọi nó là CDbLog và ghi vào cơ sở dữ liệu. Bạn có thể ghi lại những rắc rối khi trải qua 100.000 dòng và thay đổi mọi thứ từ CLog sang CDbLog không? Ngoài ra, tôi có thể có:

interface ILogger {
    virtual void write( const char* format, ... ) = 0;
};

class CLog : public ILogger { ... };

class CDbLog : public ILogger { ... };

class CLogFactory {
    ILogger* GetLog();
};

Nếu tất cả các mã đang sử dụng giao diện ILogger, tất cả những gì tôi sẽ phải thay đổi là triển khai nội bộ của CLogFactory :: GetLog (). Phần còn lại của mã sẽ tự động hoạt động mà không cần tôi phải nhấc một ngón tay.

Để biết thêm thông tin về giao diện và thiết kế OO tốt, tôi đặc biệt khuyến nghị các Nguyên tắc, Mô hình và Thực tiễn Agile của Bác Bob trong C # . Cuốn sách chứa đầy các ví dụ sử dụng trừu tượng và cung cấp các giải thích ngôn ngữ đơn giản về mọi thứ.


4

KHI NÀO đang sử dụng một singleton được đề nghị / cần thiết? Có phải là thực hành tốt?

Không bao giờ. Tồi tệ hơn thế, chúng là một con chó cái tuyệt đối để thoát khỏi, vì vậy, sai lầm này một lần có thể ám ảnh bạn trong nhiều, nhiều năm.

Sự khác biệt giữa các lớp trừu tượng và giao diện hoàn toàn không có gì trong C ++. Bạn thường có các giao diện để chỉ định một số hành vi của lớp dẫn xuất, nhưng không phải chỉ định tất cả các hành vi đó. Điều này làm cho mã của bạn linh hoạt hơn, bởi vì bạn có thể trao đổi bất kỳ lớp nào đáp ứng đặc tả hạn chế hơn. Giao diện thời gian chạy được sử dụng khi bạn cần một sự trừu tượng hóa thời gian chạy.


Các giao diện là một tập hợp con của các lớp trừu tượng. Một giao diện là một lớp trừu tượng không có phương thức xác định. (Một lớp trừu tượng không có mã nào cả.)
Gort the Robot

1
@StevenBurnap: Có thể trong một số ngôn ngữ khác.
DeadMG

4
"Giao diện" chỉ là một quy ước trong C ++. Khi tôi thấy nó được sử dụng, đó là một lớp trừu tượng chỉ có các phương thức ảo thuần túy và không có thuộc tính. Rõ ràng bạn có thể viết bất kỳ lớp cũ nào và tát một chữ "I" trước tên.
Gort Robot

Đây là cách tôi mong mọi người trả lời bài này. Một câu hỏi tại một thời điểm. Dù sao, cảm ơn bạn rất nhiều người đã chia sẻ kiến ​​thức của bạn. Cộng đồng này đáng để đầu tư thời gian.
appoll

3

Singleton rất hữu ích khi bạn không muốn có nhiều bản sao của một đối tượng cụ thể, chỉ phải có một phiên bản của lớp đó - nó được sử dụng cho các đối tượng duy trì trạng thái toàn cầu, phải xử lý mã không được gửi lại theo cách nào đó, v.v.

Một singleton có số lượng cố định từ 2 trường hợp trở lên là multiton , hãy nghĩ đến việc kết nối cơ sở dữ liệu, v.v.

Giao diện chỉ định API được xác định rõ giúp mô hình tương tác giữa các đối tượng. Trong một số trường hợp, bạn có thể có một nhóm các lớp có một số chức năng chung - nếu vậy, thay vì sao chép nó trong các triển khai, bạn có thể thêm các định nghĩa phương thức vào giao diện biến nó thành một lớp trừu tượng .

Bạn thậm chí có thể có một lớp trừu tượng trong đó tất cả các phương thức được triển khai, nhưng bạn đánh dấu nó là trừu tượng để chỉ ra rằng nó không nên được sử dụng như là không có lớp con.

Lưu ý: Giao diện & lớp trừu tượng không khác nhau nhiều trong thế giới C ++ với nhiều kế thừa, v.v., nhưng có ý nghĩa khác nhau trong Java et al.


Nói rất hay! +1
jmort253

3

Nếu bạn dừng lại để suy nghĩ về nó, tất cả là về đa hình. Bạn muốn có thể viết một đoạn mã một lần có thể làm được nhiều hơn thì người ta nghĩ tùy thuộc vào những gì bạn vượt qua nó.

Giả sử chúng ta có một hàm giống như mã Python sau:

function foo(objs):
    for obj in objs:
        obj.printToScreen()

class HappyWidget:
    def printToScreen(self):
        print "I am a happy widget"

class SadWidget:
    def printToScreen(self):
        print "I am a sad widget"

Điểm hay của chức năng này là nó sẽ có thể xử lý bất kỳ danh sách các đối tượng nào, miễn là các đối tượng đó thực hiện phương thức "printToScreen". Bạn có thể chuyển cho nó một danh sách các vật dụng hạnh phúc, một danh sách các vật dụng buồn hoặc thậm chí một danh sách có sự pha trộn của chúng và chức năng foo vẫn có thể thực hiện chính xác công việc của nó.

Chúng tôi đề cập đến loại hạn chế này là cần phải có một bộ phương thức được triển khai (trong trường hợp này là printToScreen) như một giao diện và các đối tượng thực hiện tất cả các phương thức được cho là để thực hiện giao diện.

Nếu chúng ta đang nói về một ngôn ngữ gõ vịt năng động như Python, thì bây giờ chúng ta sẽ có cơ bản kết thúc. Tuy nhiên, hệ thống kiểu tĩnh của C ++ yêu cầu chúng ta cung cấp một lớp cho các objec trong hàm của chúng ta và nó sẽ chỉ có thể làm việc với các lớp con của lớp ban đầu đó.

void foo( Printable *objs[], int n){ //Please correctme if I messed up on the type signature
    for(int i=0; i<n; i++){
        objs[i]->printToScreen();
    }
}

Trong trường hợp của chúng tôi, lý do duy nhất mà lớp Printable tồn tại là để tạo một vị trí cho phương thức printToScreen tồn tại. Do không có triển khai chia sẻ giữa các lớp thực hiện phương thức printToScreen, nên biến Printable thành một lớp trừu tượng chỉ được sử dụng như một cách để nhóm các lớp tương tự trong một hệ thống phân cấp chung.

Trong C ++, các khái niệm giao diện và lớp absctract hơi mờ. Nếu bạn muốn định nghĩa chúng tốt hơn, các lớp trừu tượng là những gì bạn đang nghĩ đến, trong khi các giao diện thông thường có nghĩa là ý tưởng ngôn ngữ chéo, tổng quát hơn của tập hợp các phương thức có thể nhìn thấy mà một đối tượng phơi bày. (Mặc dù một số ngôn ngữ, như Java, sử dụng thuật ngữ giao diện để chỉ một thứ trực tiếp hơn như một lớp cơ sở trừu tượng)

Về cơ bản, các lớp cụ thể xác định cách các đối tượng được triển khai, trong khi các lớp trừu tượng xác định cách chúng giao tiếp với phần còn lại của mã. Để làm cho các hàm của bạn đa hình hơn, bạn nên cố gắng nhận một con trỏ tới siêu lớp trừu tượng bất cứ khi nào nó có ý nghĩa để làm như vậy.


Đối với Singletons, chúng thực sự khá vô dụng, vì chúng thường có thể được thay thế chỉ bằng một nhóm các phương thức tĩnh hoặc các hàm cũ đơn giản. Tuy nhiên, đôi khi bạn có một số hạn chế buộc bạn phải sử dụng một đối tượng, mặc dù bạn không thực sự muốn sử dụng một đối tượng, do đó, mẫu đơn lẻ là phù hợp.


BTW, một số người có thể đã nhận xét rằng từ "giao diện" có ý nghĩa đặc biệt trong ngôn ngữ Java. Tôi nghĩ rằng tốt hơn là gắn bó với định nghĩa chung hơn bây giờ mặc dù.


1

Giao diện

Thật khó để hiểu mục đích của một công cụ giải quyết vấn đề mà bạn chưa bao giờ gặp phải. Tôi đã không hiểu giao diện một lúc sau khi tôi bắt đầu lập trình. Chúng tôi sẽ hiểu những gì họ đã làm, nhưng tôi không biết tại sao bạn muốn sử dụng nó.

Đây là vấn đề - bạn biết bạn muốn làm gì, nhưng bạn có nhiều cách để làm điều đó hoặc bạn có thể thay đổi cách bạn thực hiện sau này. Sẽ thật tuyệt nếu bạn có thể đóng vai trò của người quản lý không biết gì - sủa một số đơn đặt hàng và có kết quả bạn muốn mà không quan tâm đến cách thực hiện.

Giả sử bạn có một trang web nhỏ và bạn lưu tất cả thông tin của người dùng trong tệp csv. Không phải là giải pháp phức tạp nhất, nhưng nó hoạt động đủ tốt để lưu trữ thông tin người dùng của mẹ bạn. Sau đó, trang web của bạn cất cánh và bạn có 10.000 người dùng. Có lẽ đã đến lúc sử dụng một cơ sở dữ liệu thích hợp.

Nếu ban đầu bạn thông minh, bạn sẽ thấy điều này sắp tới và không thực hiện các cuộc gọi để lưu trực tiếp vào csv. Thay vào đó, bạn nghĩ về những gì bạn cần nó để làm, bất kể nó được thực hiện như thế nào. Hãy nói store()retrieve(). Bạn thực hiện một Persistergiao diện với các phương pháp trừu tượng cho store()retrieve()và tạo ra một CsvPersisterlớp con mà thực sự thực hiện các phương pháp đó.

Sau đó, bạn có thể tạo một DbPersisterchương trình thực hiện lưu trữ và truy xuất dữ liệu thực tế hoàn toàn khác với cách lớp csv của bạn đã làm điều đó.

Điều tuyệt vời là, tất cả những gì bạn phải làm bây giờ là thay đổi

Persister* prst = new CsvPersister();

đến

Persister* prst = new DbPersister();

và thế là xong. Các cuộc gọi của bạn đến prst.store()prst.retrieve()tất cả vẫn sẽ hoạt động, chúng chỉ được xử lý khác nhau "đằng sau hậu trường".

Bây giờ, bạn vẫn phải tạo các triển khai cvs và db, vì vậy bạn chưa có kinh nghiệm làm ông chủ. Những lợi ích thực sự rõ ràng khi bạn sử dụng các giao diện mà người khác tạo ra. Nếu ai đó đủ tử tế để tạo CsvPersister()DbPersister()đã có, thì bạn chỉ cần chọn một và gọi các phương thức cần thiết. Nếu bạn quyết định sử dụng cái khác sau này, hoặc trong một dự án khác, bạn đã biết nó hoạt động như thế nào.

Tôi thực sự không hài lòng với C ++ của mình, vì vậy tôi sẽ chỉ sử dụng một số ví dụ lập trình chung. Container là một ví dụ tuyệt vời về cách giao diện làm cho cuộc sống của bạn dễ dàng hơn.

Bạn có thể có Array, LinkedList, BinaryTree, vv tất cả các lớp con của Containertrong đó có phương pháp như insert(), find(), delete().

Bây giờ khi thêm một cái gì đó vào giữa danh sách được liên kết, bạn thậm chí không cần phải biết danh sách được liên kết là gì. Bạn chỉ cần gọi myLinkedList->insert(4)và nó lặp đi lặp lại một cách kỳ diệu thông qua danh sách và dán nó vào đó. Ngay cả khi bạn biết một danh sách được liên kết hoạt động như thế nào (mà bạn thực sự cần), bạn không phải tìm kiếm các chức năng cụ thể của nó, bởi vì bạn có thể đã biết những gì chúng sử dụng khác nhau Containertrước đó.

Lớp học trừu tượng

Các lớp trừu tượng khá giống với các giao diện (các giao diện kỹ thuật tốt lớp trừu tượng, nhưng ở đây tôi có nghĩa là các lớp cơ sở có một số phương thức của chúng được bổ sung.

Giả sử bạn đang tạo trò chơi và bạn cần phát hiện khi kẻ thù ở trong khoảng cách nổi bật của người chơi. Bạn có thể tạo một lớp cơ sở Enemycó một phương thức inRange(). Mặc dù có nhiều điều về kẻ thù khác nhau, phương pháp được sử dụng để kiểm tra phạm vi của chúng là phù hợp. Do đó, Enemylớp của bạn sẽ có một phương thức xác thực để kiểm tra phạm vi, nhưng các phương thức ảo thuần túy cho những thứ khác không có sự tương đồng giữa các loại kẻ thù.

Điều tuyệt vời ở đây là nếu bạn làm rối mã phát hiện phạm vi hoặc muốn điều chỉnh nó, bạn chỉ phải thay đổi nó ở một nơi.

Tất nhiên có nhiều lý do khác cho giao diện và các lớp cơ sở trừu tượng, nhưng đó là một số lý do tại sao bạn có thể sử dụng chúng.

Người độc thân

Thỉnh thoảng tôi sử dụng chúng và tôi chưa bao giờ bị chúng đốt cháy. Điều đó không có nghĩa là họ sẽ không hủy hoại cuộc sống của tôi tại một số điểm, dựa trên kinh nghiệm của những người khác.

Đây là một cuộc thảo luận tốt về nhà nước toàn cầu từ một số người có kinh nghiệm và cảnh giác hơn: Tại sao Nhà nước toàn cầu lại xấu xa như vậy?


1

Trong vương quốc động vật có nhiều loài động vật là động vật có vú. Ở đây động vật có vú là một lớp cơ sở và các động vật khác nhau bắt nguồn từ nó.

Bạn đã bao giờ nhìn thấy một động vật có vú đi bộ? Vâng, nhiều lần tôi chắc chắn - tuy nhiên chúng đều là loại động vật có vú phải không?

Bạn chưa bao giờ thấy một cái gì đó thực sự chỉ là một động vật có vú. Chúng đều là động vật có vú.

Lớp động vật có vú được yêu cầu xác định các đặc điểm và nhóm khác nhau nhưng nó không tồn tại như một thực thể vật lý.

Do đó, nó là một lớp cơ sở trừu tượng.

Làm thế nào để động vật có vú di chuyển? Họ có đi bộ, bơi, bay vv?

Không có cách nào để biết ở cấp độ động vật có vú nhưng tất cả các động vật có vú phải di chuyển bằng cách nào đó (chúng ta hãy nói rằng đây là một quy luật sinh học để làm cho ví dụ dễ dàng hơn).

Do đó MoveAround () là một hàm ảo vì mọi động vật có vú xuất phát từ lớp này cần có khả năng thực hiện nó khác nhau.

Tuy nhiên, như mọi động vật có vú PHẢI xác định MoveAround vì tất cả các động vật có vú phải di chuyển và không thể làm điều đó ở cấp độ động vật có vú. Nó phải được thực hiện bởi tất cả các lớp con nhưng ở đó nó không có ý nghĩa gì trong lớp cơ sở.

Do đó MoveAround là một hàm ảo thuần túy.

Nếu bạn có toàn bộ lớp cho phép hoạt động nhưng không thể xác định ở cấp cao nhất thì nên thực hiện như thế nào thì tất cả các hàm đều là ảo thuần và đây là giao diện.
Ví dụ: nếu chúng tôi có một trò chơi trong đó bạn sẽ mã hóa robot và gửi nó cho tôi để chiến đấu trên chiến trường, tôi cần biết tên hàm và nguyên mẫu để gọi. Tôi không quan tâm làm thế nào bạn thực hiện nó về phía bạn miễn là "giao diện" rõ ràng. Do đó tôi có thể cung cấp cho bạn một lớp giao diện mà bạn sẽ xuất phát để viết robot giết người của mình.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.