I have some actions... View, Edit, Checkout, etc. Business logic dictates that if a document is already checked out, all Views turn into Edits.
is there a neat OO way to do something like this:
class Action
{
public:
Document document;
virtual void execute();
};
class View, Edit, Checkout : public Action;
View::execute()
{
if (document.isCheckedOut)
{
delete this;
this = new E开发者_开发问答dit;
this->execute();
}
/* execute view */
}
update: what do you guys think of this:
class Action
{
public:
static int type;
Document document;
virtual void execute();
static Action* construct(int type, Document document) = 0;
private:
Action();
};
class View, Edit: public Action;
Action* View::construct(Document document)
{
if (document.isCheckedOut)
return new Edit(document);
return new View(document);
}
Action* Edit::construct(Document document)
{
return new Edit(document);
}
void onViewButton(Document document)
{
Action *action = View::construct(document);
action->execute();
delete action;
}
There's no way to re-assign the 'this' pointer like that. You could use a smart pointer implementation to do something similar by adding a layer of indirection.
class action_ptr
{
Action* m_Data;
public:
action_ptr(Action* value)
{
m_Data = value;
}
Action* operator->()
{
if(m_Data->isView() && m_Data->isCheckedOut())
{
delete m_Data;
m_Data = new Edit();
}
return m_Data;
}
};
// usage
action_ptr pAction(new View());
pAction->DoViewStuff();
pAction->Checkout();
pAction->OtherStuff(); // If isCheckedOut returned true, this now magically operates on an Edit instead!
This is by no means supposed to be a complete implementation, merely an example - there are memory leaks and many missing functions.
I would probably solve this with the strategy pattern, where the strategies have a conversion member function. Something along these lines (uninteresting code parts omitted):
struct action_strategy {
virtual ~action_strategy();
virtual action_strategy *convert_strategy(document const &doc);
virtual void execute() = 0;
};
class action { // Hur, hur :D
public:
// construct with heap-allocated strategy
action(action_strategy *strategy);
void execute() {
strategy_.reset(strategy_->convert_strategy(doc_);
strategy_->execute();
}
private:
document doc_;
std::auto_ptr<action_strategy> strategy_;
};
// Default: do nothing
action_strategy *action_strategy::convert_strategy(document const &doc) {
return this;
}
class view : public action_strategy {
// overload as necessary
virtual action_strategy *convert_strategy(document const &doc);
};
action_strategy *view::convert_strategy(document const &doc) {
if(doc.is_checked_out()) {
return new edit();
}
return this;
}
精彩评论