2015-06-02 16 views
6

Tôi đang cố gắng hiểu yêu cầu thực tế của việc sử dụng các mẫu cho thiết kế dựa trên chính sách. Trải qua các thiết kế mẫu mới trong C++ Tôi thấy rằng thiết kế lớp dựa trên chính sách là một cách thiết kế được đề xuất cao, cho phép bạn 'plug-in' các hành vi khác nhau từ các lớp chính sách. Một ví dụ nhỏ là những điều sau đây (một phiên bản rút gọn của wiki):Khi nào thích thiết kế dựa trên chính sách có khuôn mẫu hơn thiết kế dựa trên kế thừa không được lập biểu mẫu

template <typename LanguagePolicy> 
class HelloWorld : private LanguagePolicy 
{ 
    using LanguagePolicy::message; 

public: 
    // Behaviour method 
    void run() const 
    { 
     // policy methods 
     cout << message(); 
    } 
}; 

class LanguagePolicyA 
{ 
protected: 
    std::string message() const 
    { 
     return "Hello, World!"; 
    } 
}; 
//usage 
HelloWorld<LanguagePolicyA> hello_worlda; 
hello_worlda.run(); // prints "Hello, World!" 

Một phân tích nhanh chóng chỉ ra rằng chỉ để có được phương pháp plugable khác nhau message() chúng ta đang kế thừa từ một loại templated có định nghĩa có thể được cung cấp bởi bất cứ ai (và được xác định tại thời gian biên dịch).

Nhưng cùng một mức độ trừu tượng (và phương pháp cấu hình) có thể đạt được mà không cần sử dụng mã mẫu và bởi sự đa hình thời gian chạy trường đơn giản như sau.

class HelloWorld 
{ 
    LanguagePolicy *lp; //list of all plugable class 
public: 
    HelloWorld(LanguagePolicy *lpn) { 
     lp = lpn; 
    } 

    // Behaviour method 
    void run() const 
    { 
     // policy methods 
     cout << lp->message(); 
    } 
}; 
class LanguagePolicy 
{ 
protected: 
    virtual std::string message() const; 
}; 

class LanguagePolicyA: LanguagePolicy 
{ 
protected: 
    std::string message() const 
    { 
     return "Hello, World!"; 
    } 
}; 
//usage 
HelloWorld helloworld(new LanguagePolicyA); 
helloworld.run(); 

Chức năng và mức độ trừu tượng khôn ngoan tôi không thấy nhiều sự khác biệt trong cách tiếp cận hai (mặc dù cách tiếp cận thứ hai có vài dòng thêm mã cho LanguagePolicy, tôi nghĩ rằng nó là cần thiết cho những người dùng khác để biết giao diện, nếu không hiểu LanguagePolicy sẽ phụ thuộc vào tài liệu). Nhưng tôi nghĩ rằng sau này là 'sạch' (đến từ một người không sử dụng nhiều mẫu). Điều này là bởi vì cá nhân trong quan điểm của tôi không có lớp học là lớp học được sạch hơn để xem xét và hiểu. Một ví dụ cực kỳ tốt là thư viện VTK (Bộ công cụ trực quan hóa) phổ biến, giải quyết nhiều vấn đề khác nhau bằng cách sử dụng phương pháp thứ hai. Mặc dù không có tài liệu mở rộng của VTK, hầu hết chúng ta - người dùng của nó, chỉ có thể xem xét sơ đồ lớp của nó (đôi khi chúng khá lớn) và suy ra hành vi của các lớp; và phát triển các đường ống có cấu hình cao và phức tạp trong ứng dụng của chúng tôi (không thể chụp ảnh VTK thành mẫu dựa trên :)). Ngược lại là các thư viện như STL/BOOST mà tôi không nghĩ là có thể cho bất kỳ ai có thể xác định được hoạt động của các lớp mà không cần sử dụng tài liệu mở rộng.

Vì vậy, câu hỏi của tôi là, thiết kế chính sách dựa trên mẫu thực sự vượt trội (chỉ trong kịch bản này của thiết kế dựa trên chính sách) so với kế thừa dựa trên ảo? Nếu vậy, khi nào và tại sao?

Trả lời

1

Cả hai đều là cách hợp lệ để cấu trúc, nó thực sự phụ thuộc vào các yêu cầu. Ví dụ.

Thời gian chạy so với tính đa hình thời gian biên dịch.

Khi nào bạn muốn/có thể/phải đạt được sự đa hình?

Hiệu suất chi phí của các cuộc gọi ảo

Templates tạo mã mà không có indirections

Việc sử dụng thực tế của lớp.

Khi bạn phải lưu trữ bộ sưu tập không đồng nhất, cần có lớp cơ sở, vì vậy bạn phải sử dụng thừa kế.

Một cuốn sách rất tốt về thiết kế dựa trên chính sách (một chút ngày nhưng tốt vẫn) là Modern C++ Design

+0

-> Mẫu 'mô phỏng' polymerphism thời gian chạy bằng cách tạo các lớp tại thời gian biên dịch. Vì vậy, tại sao không sử dụng thời gian chạy trực tiếp? Tại sao chúng ta quan tâm? -> Tôi sẽ xem xét, nhưng chi phí cho cuộc gọi ảo thực sự là bao nhiêu? Là đủ quan trọng để gây ra một hiệu ứng? – krips89

+0

@ krips89 Điểm thứ hai. Có một chi phí hiệu năng với các cuộc gọi ảo, điều này có thể quan trọng trong một số trường hợp. –

+0

@ krips89 Nó phụ thuộc nhưng nếu bạn xem xét đến sự gián đoạn, sự lộn xộn với các dòng bộ nhớ cache, khả năng của một chức năng được tạo khuôn mẫu được gạch chân, có thể có được lợi ích từ việc sử dụng các chính sách. –

1

Phụ thuộc vào tình hình tôi đoán ...Nhược điểm có thể xảy ra khi sử dụng mẫu là loại phải được biết tại thời điểm biên dịch:

HelloWorld<English> hw; // English is plugged at compile-time 

Trong ví dụ thứ hai, nơi bạn đang sử dụng con trỏ đến cơ sở, con trỏ này có thể trỏ đến nhiều các lớp dẫn xuất. Chính xác những gì nó trỏ đến là không cần thiết để được biết tại thời gian biên dịch và do đó có thể được xác định bởi (người dùng) đầu vào khi chạy. Một bên có thể xuống của phương pháp này là chi phí cuộc gọi ảo. Trong một số ứng dụng và trên một số nền tảng, điều này có thể không mong muốn.

+0

Có; theo như tôi hiểu cho đến bây giờ, vấn đề duy nhất xuất hiện trong phương pháp thứ hai là 'phí gọi điện thoại ảo'. Nếu tôi nhìn hoàn toàn trong quan điểm thiết kế (mà không quan tâm đến chi phí thực hiện) thì cách tiếp cận thứ hai là tốt hơn. – krips89

+0

Đó là nhược điểm duy nhất tôi có thể nghĩ đến ngay bây giờ. Ngày đầu đó, các cơ sở trừu tượng giúp bắt buộc một giao diện trên các lớp dẫn xuất, mà là tốt đẹp. Kiểm tra giao diện tĩnh có thể sẽ có sẵn trong C++ 17 khi các khái niệm được thêm vào ngôn ngữ mặc dù (tuyệt vời). – JorenHeit

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