2010-11-03 40 views
9

Giả sử có một lớp trừu tượng với một hàm tạo gọi một phương thức trừu tượng được bảo vệ chưa được lớp con thực hiện. Đây có phải là một ý tưởng tốt hay xấu? Tại sao?OOP tốt hay xấu?

+3

Có. các lớp trừu tượng là một ý tưởng tồi. – tidwall

+0

Các lớp trừu tượng không phải là một ý tưởng tồi - chỉ có khả năng gọi các phương thức ảo từ bên trong một hàm tạo. Ý tưởng cũng xấu cho các lớp cụ thể - không chỉ trừu tượng;) –

+0

@Reed, không, các lớp trừu tượng là một ý tưởng tồi (mặc dù vì các lý do khác). Thông thường, ủy nhiệm/tập hợp là một cơ chế tốt hơn, ít bị lỗi để tái sử dụng mã hơn là thừa kế. Giao tiếp thừa kế là tốt (tức là không thực hiện), nhưng thừa kế lớp là một ý tưởng khủng khiếp. –

Trả lời

3

Đây là một ý tưởng tồi.

Về cơ bản, bạn đang tạo ra sự đảo ngược kiểm soát trong một hàm tạo. Phương thức trong lớp cơ sở đang được gọi được gọi trước khi dữ liệu lớp cơ sở được khởi tạo (trong hầu hết các ngôn ngữ), cũng rất nguy hiểm. Nó có thể dễ dàng dẫn đến hành vi không xác định.

Hãy nhớ rằng, trong hầu hết các ngôn ngữ, khi bạn xây dựng một lớp, tất cả các cấu trúc lớp cơ sở sẽ chạy trước tiên. Vì vậy, nếu bạn có một cái gì đó như: MyClass() : MyBaseClass() {}, thông thường, hàm xây dựng của MyBaseClass chạy toàn bộ, thìMyClass của hàm tạo thi hành. Tuy nhiên, bằng cách sử dụng một phương thức ảo trong lớp cơ sở, bạn đang gọi một phương thức cá thể trong MyClass trước khi nó được khởi tạo hoàn toàn - điều này có thể rất nguy hiểm.

+0

Điểm tốt. Cảm ơn sự hiểu biết của bạn. – StackOverflowNewbie

2

Đây là một ý tưởng tồi, bởi vì trong hầu hết các ngôn ngữ OOP, đứa trẻ được khởi tạo sau khi cha mẹ được khởi tạo. Nếu chức năng trừu tượng được thực hiện trong đứa trẻ, sau đó nó có thể hoạt động trên dữ liệu trong các con theo giả định không chính xác rằng nó đã được khởi tạo, mà không phải là trường hợp trong xây dựng cha mẹ.

Ví dụ:

class Base { 
    public: 
     Base() { virtualInit(); } 
     virtual ~Base() {} 
    protected: 
     virtual void virtualInit() {} 
}; 

class Derived : public Base { 
    public: 
     Derived() : ptr_(new SomeObject) {} 
     virtual ~Derived() {} 
    protected: 
     virtual void virtualInit() { 
       // dereference ptr_ 
     } 
    private: 
     scoped_ptr<SomeObject> ptr_; 
}; 

Trong ví dụ trên, Base::Base() được thực hiện trước khi Derived::Derived(), đó là trách nhiệm khởi ptr_. Do đó, khi virtualInit() được gọi là từ Base::Base() nó dereferences một con trỏ uninitialized, dẫn đến tất cả các loại rắc rối. Đây là lý do tại sao ctors và dtors chỉ nên gọi các hàm không phải ảo (trong C++), các hàm cuối cùng (trong Java), hoặc tương đương với ngôn ngữ cụ thể.

1

Tôi không thể thấy lý do tại sao bạn muốn làm điều này, hãy để một mình hội đủ điều kiện. Có vẻ như bạn đang cố tiêm một số chức năng vào đối tượng. Tại sao bạn không chỉ quá tải constructor hoặc tạo một thuộc tính có thể được thiết lập để bạn có thể inject các chức năng thông qua composition hoặc thậm chí tạo constructor với tham số là đối tượng IOC.

Khi người khác đã đăng, điều đó phụ thuộc vào ngữ cảnh mà trong đó bạn đang cố giải quyết một vấn đề cụ thể. Sự phù hợp tự nhiên sẽ tuân thủ một giao diện, phát triển một lớp trừu tượng và quá tải các hàm tạo trong mỗi lần thực hiện. Nếu không có thêm thông tin, tôi chỉ có thể bình luận về những gì đã được đăng trong câu hỏi của bạn.

Thiết kế này bạn không thể coi là tốt hay xấu. Chỉ đơn giản là từ thực tế rằng nó có thể là cách duy nhất bạn có thể đạt được những gì bạn đang cố gắng làm.

+0

Cảm ơn bạn đã nhập. Tôi không thực sự cố gắng giải quyết một vấn đề cụ thể. Chỉ cần hỏi ý kiến ​​cho một giải pháp thiết kế có thể. – StackOverflowNewbie

+0

giao diện tốt hơn như thế nào? Điều gì xảy ra nếu tôi cần một lớp học chung cho tất cả các lớp học để kế thừa? Các lớp phổ biến chính nó không nên được instantiated trực tiếp, nhưng có chứa một số phương pháp và tài sản mà các lớp hậu duệ cần? Bạn sẽ không cần một lớp trừu tượng để bạn có thể hưởng lợi từ thừa kế? – StackOverflowNewbie

+0

Sở thích cá nhân, tôi luôn luôn làm thành phần thừa kế trong thiết kế chương trình của mình. Tôi thấy các giải pháp mạnh mẽ hơn. Tôi sẽ xem xét vấn đề bằng cách sử dụng phương pháp CRC và làm việc ra các tương tác nhiều hơn thừa kế. Một đối tượng có trách nhiệm và nên rất giỏi. Nó cũng có thể được thay thế bằng một loại tương tự khác. Do đó, tôi sẽ xem xét các hành vi và thiết kế xung quanh những hành vi này trước tiên. Không nói rằng tôi sẽ không làm thừa kế, nhưng nó không phải cái gì tôi nghĩ từ lúc khởi phát, nó thường xảy ra xuống dòng khi tôi tái yếu tố. – WeNeedAnswers

0

Chỉ sau đó là một ý tưởng TỐT, IFF bạn có thể quản lý nó để không bắn vào chân của bạn. Nhưng dù sao, OOP luôn dễ bị thiết kế xấu; vì vậy nếu ngôn ngữ của bạn cho phép các mô hình khác hơn OOP, để sử dụng OOP trong trường hợp này chắc chắn là một sự lựa chọn BAD.

Ít nhất trong C++, lớp con xác định trình tự tất cả các khởi tạo được tạo; đó là khởi tạo của tất cả các biến thành viên và các hàm tạo của tất cả các lớp cha. Điều này đã được xem xét!

Hoặc, bạn có thể cung cấp cho hàm tạo (như tham số) một con trỏ tới một hàm cụ thể (tôi thích các hàm tĩnh), thay vì gọi hàm trừu tượng thành viên.Đây có thể là một giải pháp thanh lịch và lành mạnh hơn nhiều; và đây là giải pháp thông thường trong (có thể là tất cả) ngôn ngữ không phải là OOP. (trong java: Một con trỏ trỏ tới một hàm hoặc một danh sách các hàm là mẫu thiết kế của một giao diện và ngược lại.)

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