如何在使用装饰器和迭代器设计模式时声明友类

How to declare friend classes while using decorator and iterator design patterns

本文关键字:设计模式 迭代器 声明      更新时间:2023-10-16

我通过装饰ListAsSLL类(单链表)创建了一个ListAsDLL类(双链表)。现在我想合并一个Iterator类来循环ListAsDLL类。我的代码如下:

#include <iostream>
using namespace std;
class ListAsSLL
{
protected:
    struct node{
        int i;
        struct node* next;
    };
    node* head;
    node* tail;
    int listSize;
public:
    ListAsSLL()
    {
        head = 0;
        tail = 0;
        listSize = 0;
    }
    virtual void addToBeginning(int i)
    {
        node * temp = new node;
        temp->i = i;
        if(head==0){
            temp->next = 0;
            tail = temp;
        }else if(head == tail) {
            temp->next = tail;
        }
        else{
            temp->next = head;
        }
        head = temp;
        listSize++;
    }
    virtual void print()
    {
        node* temp = head;
        for (int i = 0; i < listSize; ++i) {
            cout<<temp->i<<" "<<endl;
            temp = temp->next;
        }
    }
};
class Decorator : public ListAsSLL
{
private:
    ListAsSLL* list;
public:
    Decorator(ListAsSLL* l)
    {
        list = l;
    }
    virtual void addToBeginning(int i)
    {
        list->addToBeginning(i);
    }
    virtual void print()
    {
        list->print();
    }
};
class PreviousDecorator : public Decorator
{
protected:
    struct dnode : public node
    {
        node* prev;
    };
    dnode* head;
    dnode* tail;
    int listSize;
public:
    PreviousDecorator(ListAsSLL* l) : Decorator(l)
    {
        listSize = 0;
        head = 0;
        tail = 0;
    }
    virtual void addToBeginning(int i)
    {
        Decorator::addToBeginning(i);
        dnode * temp = new dnode;
        temp->i = i;
        if(head==0){
            temp->next = 0;
            tail = temp;
        }else if(head == tail) {
            temp->next = tail;
            tail->prev = temp;
        }
        else{
            temp->next = head;
            tail->prev = temp;
        }
        temp->prev = 0;
        head = temp;
        listSize++;
    }
    virtual void print()
    {
        Decorator::print();
        node* temp = head;
        for (int i = 0; i < listSize; ++i) {
            cout<<temp->i<<" "<<endl;
            temp = temp->next;
        }
    }
    friend class DLLIterator;
};
class ListAsDLL : public ListAsSLL
{
public:
    virtual void addToBeginning(int i){}
    virtual void print(){}
};
class DLLIterator
{
private:
    ListAsDLL* dll;
public:
    DLLIterator(ListAsDLL* dll)
    {
        this->dll = dll;
    }
    int getFirst()
    {
        return dll->head->i;
    }
};
int main() {
    ListAsSLL* dll = new PreviousDecorator(new ListAsDLL());
    dll->addToBeginning(20);
    DLLIterator* it = new DLLIterator((ListAsDLL*) dll);
    cout<<it->getFirst()<<endl;
    delete dll;
    delete it;
    return 0;
}

唯一的问题是,因为我正在传递ListAsDLL作为参数到Iterator类,我无法访问它正在装饰的类的受保护属性。因此我不能访问dll->head-> I .

首先,我是否正确地使用了decorator设计模式?其次,我如何访问一个被友类装饰过的类的受保护属性呢?

你的类层次结构是:

ListAsSSL (a first head) <- Decorator <- PreviousDecorator (another head)
    ^
    |---- ListAsDLL

不能将PreviousDecorator强制转换为ListAsDLL,即使它们有共同的基类。此外,在PreviousDecorator::addToBeginning方法中,您写入PreviousDecorator::head而不是ListAsSSL::head,从而保留nullptr

当您想要定制单元格时,一种解决方案可以是使用像createEmptyNode这样的虚拟方法在类ListAsSLL的级别上打开节点的类型。ListAsDLL可以重写此方法以创建双链接节点,如下面的代码所示。

#include <iostream>
using namespace std;
class ListAsSLL
{
protected:
    struct node{
        int i;
        struct node* next;
    };
    node* head;
    node* tail;
    int listSize;
public:
    ListAsSLL()
    {
        head = 0;
        tail = 0;
        listSize = 0;
    }
    virtual node* createEmptyNode() const { return new node{}; }
    virtual node* addToBeginning(int i)
    {
        node * temp = createEmptyNode();
        temp->i = i;
        if(head==0){
            temp->next = 0;
            tail = temp;
        }else if(head == tail) {
            temp->next = tail;
        }
        else{
            temp->next = head;
        }
        head = temp;
        listSize++;
        return temp;
    }
    virtual void print()
    {
        node* temp = head;
        for (int i = 0; i < listSize; ++i) {
            cout<<temp->i<<" "<<endl;
            temp = temp->next;
        }
    }
};
class ListAsDLL : public ListAsSLL
{
protected:
    struct dnode : public node
    {
        dnode* prev;
    };
    virtual node* createEmptyNode() const { return new dnode{}; }
public:
    virtual node* addToBeginning(int i)
    {  node* result = ListAsSLL::addToBeginning(i);
       static_cast<dnode*>(tail)->next = static_cast<dnode*>(result);
       static_cast<dnode*>(result)->prev = static_cast<dnode*>(tail);
    }
    virtual void print(){}
    friend class DLLIterator;
};
class DLLIterator
{
private:
    ListAsDLL* dll;
public:
    DLLIterator(ListAsDLL* dll)
    {
        this->dll = dll;
    }
    int getFirst()
    {
        return dll->head->i;
    }
};
int main() {
    ListAsSLL* dll = new ListAsDLL();
    dll->addToBeginning(20);
    DLLIterator* it = new DLLIterator((ListAsDLL*) dll);
    cout<<it->getFirst()<<endl;
    delete dll;
    delete it;
    return 0;
}

下面的代码使用了具有新的层次结构级别的装饰器模式来避免数据重复。ListAsSLL表示可以管理单链接单元格和双链接单元格的实现。

新的类层次结构是:

List <- ListAsSSL (implementation = head, tail)
  ^
  |- Decorator (SLL) <- PreviousDecorator (DLL)

我保留了类的原始名称,但您可以修改它们。

#include <iostream>
#include <cassert>
#include <memory>
using namespace std;
class List {
  public:
   virtual ~List() {}
   virtual void addToBeginning(int i) {}
   virtual void print() const {}
   virtual int getFirst() const { assert(false); }
};
class PreviousDecorator;
class ListAsSLL : public List
{
protected:
    struct node{
        int i;
        struct node* next;
        node(int val) : i(val), next(nullptr) {}
    };
    node* head;
    node* tail;
    int listSize;
    friend class PreviousDecorator;
public:
    ListAsSLL()
    {
        head = 0;
        tail = 0;
        listSize = 0;
    }
    virtual ~ListAsSLL()
       { node* cell = head; 
         for (int i=0; i<listSize; ++i) {
           node* temp = cell->next;
           delete cell;
           cell = temp;
         }
       }
    void addToBeginning(node* anode)
    {
        node * temp = anode;
        if(head==0){
            temp->next = 0;
            tail = temp;
        }else if(head == tail) {
            temp->next = tail;
        }
        else{
            temp->next = head;
        }
        head = temp;
        listSize++;
    }
    virtual void addToBeginning(int i) { addToBeginning(new node(i)); }
    virtual void print() const
    {
        node* temp = head;
        for (int i = 0; i < listSize; ++i) {
            cout<<temp->i<<" "<<endl;
            temp = temp->next;
        }
    }
    virtual int getFirst() const { assert(head); return head->i; }
};
class Decorator : public List
{
private:
    std::unique_ptr<ListAsSLL> list;
protected:
    ListAsSLL& getImplementation() { return *list; }
public:
    Decorator(ListAsSLL* l) : list(l) {}
    virtual void addToBeginning(int i)
    {
        list->addToBeginning(i);
    }
    virtual void print() const
    {
        list->print();
    }
    virtual int getFirst() const { return list->getFirst(); }
};
class DLLIterator;
class PreviousDecorator : public Decorator
{
protected:
    struct dnode : public ListAsSLL::node
    {
        node* prev;
        dnode(int val) : node(val), prev(nullptr) {}
    };
public:
    PreviousDecorator(ListAsSLL* l) : Decorator(l) {}
    virtual void addToBeginning(int i)
    {   dnode* anode = new dnode(i);
        getImplementation().addToBeginning(anode);
        anode->prev = static_cast<dnode*>(getImplementation().tail);
        getImplementation().tail->next = anode;
    }
    friend class DLLIterator;
};
class DLLIterator
{
private:
    PreviousDecorator* dll;
public:
    DLLIterator(PreviousDecorator* dll)
    {
        this->dll = dll;
    }
    int getFirst() const
    {   
        return dll->getFirst();
    }
};
int main() {
    PreviousDecorator* dll = new PreviousDecorator(new ListAsSLL());
    dll->addToBeginning(20);
    cout<<dll->getFirst()<<endl;
    delete dll;
    return 0;
}