lundi 22 février 2016

Composite pattern with visitor, what really goes in visitor and how?

Composite pattern is often used with visitor. I am trying to figure out what exactly goes into composite and what in visitor. For example if one of the composite has unique property/attribute, will it still be stored in it and visitor will only dig it out or visitor will keep it?

I have written a quick demo to illustrate the problem (note: I have minimized code).

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 );
}

In this example, an employee can have a lot of attributes, some of them differ from one another depending on what kind of employee it is.

For example SalesPerson has a territory attribute which is not applicable to other employees, does the composite still store it and visitor only retrieves its value? In that case will we need two visitors to setValue() and getValue() if I need these operations? The 2nd paradigm is should the visitor instead store this attribute, in essence add this property which would otherwise not exist in employee?

How about stock options property which is lets assume is given only to 5% employees. Should this be stored in composite and extended by visitor?

One of my concern is employee composite can have many additional attributes which could also mean differences widening up in derived class. Is it okay if composite has relatively large attributes that doesn't actually apply to all sub classes? Should we add property via visitor or only use visitor to provide interface to the specific additional properties that a unique subclass may have?

Aucun commentaire:

Enregistrer un commentaire