Frage

I'm writing an application that has "tasks" (actually, steps in a holiday) that have some (minimal) degree of overlap. A standard task is more or less designed like this (trimmed the private members):

#include <QMetaType>
#include <QString>
#include <QDateTime>
#include <QVector>

namespace Marble
{
class GeoDataPlacemark;
}

namespace HolidayPlanner
{

class HolidayTask: public QObject
{

    Q_OBJECT

public:

    explicit HolidayTask(QString name, ActivityType type=Lodging, QObject* parent=0);

    virtual ~HolidayTask();

    QString name() const;
    QString description() const;

    Marble::GeoDataPlacemark *location() const;
    virtual ActivityType type() const;

    const QDateTime startDate() const;
    const QDateTime endDate() const;

    void setName(const QString &name);
    void setDescription(const QString &description);

    void setStartDate(const QDateTime &dateTime);
    void setStartDate(int year, int month, int day, int hour, int minutes);

    void setEndDate(const QDateTime &dateTime);
    void setEndDate(int year, int month, int day, int hour, int minutes);

    void setLocation(Marble::GeoDataPlacemark *location);
    // private members, etc... 
};

} // namespace HolidayPlanner

The issue now is how to define tasks, e.g. a single class or a base class inherited by other classes. To be clearer:

  • Tasks have usually a name and a description
  • All of them have start dates, some of them end dates
  • Some have a single location (e.g. a city), others have two (e.g. from and to)
  • A type() function returns the "type" of the task (a flag from an enum)
  • The application will need to handle data slightly differently depending on the task (i.e. don't show "from" and "to" widgets if you are using a single location task, etc...)

I initially settled by a single class + a derived class to handle the "from location" and "to location case", but I'm not sure it is too clean. On the other hand, I'm not sure creating a base class with just the common methods (name() and description(), perhaps startDate() and endDate()) would make much sense.

What would be the best course of action, given the above use case?

War es hilfreich?

Lösung

I disagree that composition is better then inheritance. Can one not always use composition if forced? Yes, but it might not be best....eg virtual functions, containers of base object types.

I prefer the IS-A and HAS-A tests to determine what to.

  • Tasks have usually a name and a description - Pure virtual functions (aka an interface) in the base if these are constants for the derived object. Otherwise just members.
  • All of them have start dates, some of them end dates - start --> base, end -->derived
  • Some have a single location (e.g. a city), others have two (e.g. from and to) - A vector of locations (three legs, four?) in base
  • A type() function returns the "type" of the task (a flag from an enum) - Make it a pure virtual function in the base (aka an interface)
  • The application will need to handle data slightly differently depending on the task (i.e. don't show "from" and "to" widgets if you are using a single location task, etc...) - Read about model/view/controller (MVC).

Andere Tipps

Its always better to use composition over inheritance if possible. But also if you have many of the same items for each type of task you can easily have a base class and then derive from that and have an overloaded function for the additional locations like you mention above and then derived classes can have its own methods for its personal manipulation of that task.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top