复合模式通常与访问者一起使用。我试图弄清楚到底什么进入了复合 Material ,什么进入了访问者。例如,如果其中一个组合具有独特的特性/属性,它是否仍会存储在其中并且访问者只会将其挖掘出来或访问者会保留它?
我已经编写了一个快速演示来说明问题(注意:我已将代码最小化)。
using namespace std;
class Visitor
{
public:
virtual string visit(class Manager * manager) = 0;
virtual string visit(class SalesPerson * salesPerson) = 0;
};
class Employee
{
public:
virtual void add(Employee * employee) = 0;
virtual void remove(Employee * employee) = 0;
virtual string name() = 0;
virtual string department() = 0;
virtual int salary() = 0;
virtual void awardBonus(int amount) = 0;
virtual void accept(Visitor * v) = 0;
protected:
string m_name;
string m_dept;
int m_salary;
};
class Manager : public Employee
{
protected:
QList <Employee *> subordinates;
virtual void add(Employee * employee)
{
subordinates.append( employee );
}
virtual void remove(Employee * employee) {};
virtual string name() { return m_name; };
virtual string department() { return m_dept; };
virtual int salary() { return m_salary; };
virtual void awardBonus(int amount) {};
void accept(Visitor *v)
{
v->visit(this);
}
};
class SalesPerson: public Employee
{
public:
float commision; // sales employee gets commision
string territory;
SalesPerson(): territory("Unknown") {};
void accept(Visitor *v)
{
v->visit(this);
}
virtual void add(Employee * employee) {};
virtual void remove(Employee * employee) {};
virtual string name() { return m_name; };
virtual string department() { return m_dept; };
virtual int salary() { return m_salary; };
virtual void awardBonus(int amount) {};
};
class AwardStockOptionsVisitor : public Visitor
{
public:
int shares;
string visit(Manager *manager)
{
shares = 200;
}
string visit(SalesPerson *salesPerson)
{
shares = 100;
}
};
class GetTerritoryVisitor : public Visitor
{
public:
string territory;
string visit(Manager *manager)
{
return "";
}
string visit(SalesPerson *salesPerson)
{
territory = salesPerson->territory;
return salesPerson->territory;
}
};
int main(int argc, char *argv[])
{
Employee * manager = new Manager;
Employee * salesPerson = new SalesPerson;
GetTerritoryVisitor * getTerritory = new GetTerritoryVisitor;
salesPerson->accept( getTerritory );
cout << "Sales territory is " << getTerritory->territory << endl;
manager->add( salesPerson );
}
在此示例中,一名员工可以有很多属性,其中一些属性因员工类型而异。
例如 SalesPerson 有一个 territory 属性,它不适用于其他员工,组合是否仍然存储它而 visitor 只检索它的值?在那种情况下,如果我需要这些操作,我们是否需要两个访问者访问 setValue()
和 getValue()
?第二个范例是访问者是否应该存储这个属性,本质上是添加这个在员工中不存在的属性?
我们假设股票期权属性(property)只提供给 5% 的员工。这应该存储在组合中并由访问者扩展吗?
我担心的一个问题是 employee composite 可以有许多额外的属性,这也可能意味着派生类中的差异会扩大。如果 composite 具有相对较大的属性但实际上并不适用于所有子类,这可以吗?我们应该通过访问者添加属性,还是仅使用访问者来为唯一子类可能具有的特定附加属性提供接口(interface)?
最佳答案
虽然这两种设计模式是互补的,但它们的意图是不同的:
根据这个原则,访问者不是用来存储持久数据的。所以,是的,可能特定于某类员工的任何属性都应保留在组合中。
您拥有大量属性集(无论是特定于某个员工派生的还是所有员工共有的)这一事实不会改变原则。访问者模式旨在处理组合中不同类型的元素,使用不同的访问成员函数(每个不同的类一个)。
唯一的不便之处是,当您向复合结构中添加新类时,您需要相应地修改访问者。
您可以暂时将一些值放入访问者中以执行操作。例如:
- 你可以有一个访问者来汇总经理下面的人数,以及他们的总薪水
- 或者您可以拥有访问者的股份总数,这会实现一种算法,以分层方式将这些股份分配给员工。在分配结束时,访客中剩余的股份将为 0,因此您需要在组合中有一些股东计数器。
实现问题:
您的访问者模式实现不完整。您没有通过复合结构的访问逻辑。
看看您打算使用访问者的方式,我想知道您是否正在寻找向对象添加属性/功能,而不是浏览它们。
我建议你看看 decorator pattern ,它更适合这种用法:它是一种结构模式,扩展了现有的类族。
关于c++ - 与访问者的复合模式,访问者真正进入了什么以及如何?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35561441/