2012-12-13 22 views
11

Tôi có một mô hình thực hiện tổng hợp, được sử dụng cho các thành phần GUI:Khả năng trộn Composite Pattern và mẫu hoa văn một cách tò mò định kỳ

class CObject { 
private: 

    CObject * m_pParent; 
    CObjectContainer * m_pChildren; 

    void private_foo() { 
    this->foo(); 
    //Calls private_foo for each child in container. 
    m_pChildren->foo(); 
    } 

public: 
    virtual void foo() { 
    //empty for base class 
    } 

    virtual CObject * duplicate() { 
    //Do duplication code 
    return new CObject(*this); 
    } 

    virtual CObject * detach() { 
    //Remove this object (along with it's children) 
    //from current tree. 
    m_pParent->RemoveChild(this); 
    m_pParent = nullptr; 
    return this; 
    } 
} 

class CSpecificObject : public CObject { 
public: 
    virtual void foo() { 
    //Specific code for this class 
    } 

    virtual CSpecificObject * duplicate() { 
    //Overload, but the code only calls diferent constructor 
    return new CSpecificObject(*this); 
    } 

    virtual CSpecificObject * detach() { 
    //Note the code is identical. 
    m_pParent->RemoveChild(this); 
    m_pParent = nullptr; 
    return this; 
    } 
} 

Đáng tiếc là số lượng các lớp học di truyền tăng lên nhanh chóng và mã trùng lặp (trong ví dụ đưa ra chỉ các Phương thức detach() đang khiến tôi đau đầu.

Có cách nào để thực hiện sạch các phương thức tách rời(), giữ kiểu trả về giống với đối tượng mà trên đó nó được gọi không?

Tôi đã suy nghĩ về CRTP, nhưng tôi không thể nghĩ ra một cách để giữ cho đa hình năng động cùng với thời gian biên dịch đa hình:

template <Child> 
class CObject { 
private: 
    ... 
    Child * detach() { 
    m_pParent->RemoveChild(this); 
    m_pParent = nullptr; 
    return static_cast<Child*>(this); 
    } 
    ... 
} 

//Array of CObject* pointers is no longer possible. 

Trả lời

6

Bạn có thể thêm một mức độ trừu tượng:

class CObjectBase 
{ 
    public: 
     // Other methods... 
     virtual CObjectBase* detach() = 0; 
     virtual CObjectBase* duplicate() const = 0; 
}; 

template <typename Child> 
class CObject : public CObjectBase 
{ 
    public: 
     // ... 
     Child* duplicate() const 
     { 
      return new Child(*static_cast<Child*>(this)); 
     } 

     Child* detach() 
     { 
      m_pParent->RemoveChild(this); 
      m_pParent = nullptr; 
      return static_cast<Child*>(this); // Cast needed here (inherent to CRTP) 
     } 
     std::vector<CObjectBase*> children; // Array possible now 
     // ... 
}; 

class MyObject : public CObject<MyObject> 
{ 
    // ... 
}; 

Trong ngôn ngữ tự nhiên: một giao diện cho tất cả các đối tượng (CObjectBase) có một phần thực hiện cho con cháu của nó (CObject<Child>), mà chỉ phải thừa kế thực hiện một phần này, giảm số lượng mã nhân rộng.

1

Tôi đã suy nghĩ về CRTP, nhưng tôi không thể nghĩ ra một cách để giữ cho đa hình năng động cùng với thời gian biên dịch đa hình

Bạn có thể kết hợp chúng bằng cách cung cấp mặc định triển khai ảo cho các giao diện nhất định sử dụng CRTP các lớp cơ sở phong cách.

Vì vậy, bạn có khả năng tổng hợp các triển khai cơ sở CRTP (có thể được định cấu hình với các tham số mẫu chính sách bổ sung) và vẫn có thể ghi đè hành vi cụ thể trong các lớp kế thừa.

Microsoft ATL library sử dụng điều này rất nhiều. Tôi cũng sử dụng kỹ thuật này trong STTCL state machine library của mình.

1

Chỉ từ đoạn mã, không rõ lý do bạn cần detach() để trả lại con trỏ cho loại được phân phối.

Để tận dụng lợi thế của detach() trả về loại được phân phối, nó cần phải được gọi bằng cách sử dụng tham chiếu đến loại được phân phối. Như thế này:

CSpecificObject* specific_object = new SpecificObject(); 
// ... 
specific_object->detach()->method_declared_in_specific_object(); 

Nhưng điều này có thể được thay thế bằng tương đương mà làm việc ngay cả khi cửa sổ mới là void:

specific_object->detach(); 
specific_object->method_declared_in_specific_object(); 

Nếu bạn có một tham chiếu đến các loại hình cơ bản, bạn không thể tận dụng lợi thế của detach() loại trả lại:

CObject* specific_object = new SpecificObject(); 
//... 
// !!! Won't compile: 
specific_object->detach()->method_declared_in_specific_object(); 

Vì lý do này, không rõ lợi thế của phương pháp bạn đang cố triển khai là gì.

Một mặt không phải là phương pháp duplicate() có mùi. Nó phá vỡ khi lớp được phân phối không ghi đè lên nó, nhưng sử dụng việc thực hiện mặc định từ lớp cha. Nó có thể là một dấu hiệu cho thấy có điều gì đó sai với thiết kế cấp cao.

+0

'Mở cửa sổ mới() 'phương pháp được sử dụng trong một cách xấu xí: ' CObject * tree_of_stuff;' - Một cây đầy đủ của các đối tượng 'CSpecificObject * specific_object = tree_of_stuff-> Trẻ em ("StringId") -> split(); ' Phương thức' Child <>() 'thực hiện tìm kiếm dọc theo cây và đưa đối tượng vào tham số mẫu được chỉ định. Cú pháp này không có sẵn nếu 'detach()' trả về 'void' hoặc' CObject * '. –

+1

Phương thức 'duplicate()' là một nguồn lỗi nhất định, đó là một trong những lý do tôi mở rộng mẫu hiện tại bằng CRTP. Theo quan điểm của tôi, dựa vào constructor sao chép là an toàn hơn khi hứa rằng mọi người sẽ thực hiện phương thức 'duplicate()'. –

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