Link to home
Start Free TrialLog in
Avatar of mrwad99
mrwad99Flag for United Kingdom of Great Britain and Northern Ireland

asked on

Chain of responsibility design pattern: query

Ah hello.

I have read about the chain of responsibility design pattern (http://www.pluralsight.com/articlecontent/cpprep0796.htm) and am implementing it in a simple dialog based application.  However, I have come across a concern, and am wondering if how I am about to implement this pattern is correct or not.

I have a dialog class CMyDlg.  I have a custom command target class CMyCommandTarget.  The dialog class has an instance of the command target class, and in its OnCmdMsg function, it forwards commands to this command target, just as in the example linked to above.  Now, say I have a button on my dialog, that, when clicked, is to disable another button on the dialog.  So I have

CMyCommandTarget::OnBnClicked()
{
      // Disable some button, say, with ID IDC_MYBUTTON, or, even better,
      // CMyDlg::m_myButton with DDX
}

How does CMyCommandTarget know about IDC_MYBUTTON, or CMyDlg::m_myButton ?  (I know there are many obvious ways of doing this, but *I want to do it the best way*).

I am considering:

1) Pass a pointer to the dialog in the CMyCommandTarget constructor, and access controls via access functions.

2) Do the same as 1), except make the command target class a friend of the dialog, thereby avoiding excessive access functions.

3) A suggestion by you experts ??

What is the proper way, and the way that pro programmers use ?  (There are enough of you participate on EE, so someone must have come across this.)

TIA
Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

<I have a custom command target class CMyCommandTarget>

I have a horrible feeling you have misunderstood the article (or I have).
Have a read in the 'Prosise' book about command routing.  That is very similar to the article.  It describes how windows routes messages though frames, views documents and the app.


I don't think you need a custom CCommandTarget, nor do I think the article recommends that.  You just need to derive your class from CCommandTarget to make use of the default message routing.  As long as the class is derived from it you can safely modify the OnCmdMessage of the view/doc/whatever by patching in code like
  if (m_pMyOb != 0 && m_pMyOb->OnCmdMsg(command, ...))
    return TRUE;
this will pass the message onto an object - returns true if it handles it and this stops the chain


What you want to implement (I think) is code in your dialog class itself.  In the OnCmdMessage in the dialog you enable/disable the buttons - GetDlgItem(IDC_MYBTN)->EnableWindow(flag); - depending on some state.
Thinking about it I think my final paragraph should be ignored.

I think you want to know why you have a button IDC_BTN_DOSOMETHING without a click event handler in your dialog but that the button is not disabled.  Is that what you want?  (An alternative question would be how to use the ON_COMMAND_UI for buttons on the dialog)
Avatar of mrwad99

ASKER

Andy

I have not forgotten this Q.  I will re-read the article and then come back.  Thanks.
No probs.
Avatar of mrwad99

ASKER

Right, hopefully you have not forgotten about this too much...

The article is discussing a pattern that, as you have noticed, is already implemented in MFC.  I have however seen code where all the commands from a particular part of the application (eg those invoked through some specific menu, or those for a particular action) have been handled in separate command target classes.  For example, we could have an app that has a large "Insert" menu option.  This could allow a multitude of actions to be carried out, as there may be a multitude of menu options. (Consider something like a photo editing program, where we can insert objects and effects onto the current document.  Each of these options would be a submenu, with their own possible submenus catering for all the different effects of types of object we could insert.)  If the app was an MDI, chances are the majority of these commands would be handled in the view class.  

Now, if we have, say, 100 total different options spanning from our insert menu, we would have to have 100 handlers of the type

ON_COMMAND(<ID>, <HANDLER FUNCTION>)

along with each of the functions themselves.  This is a lot of code to have in one source file.

What I think the article is getting at is what I have noted in other code: a separate command object that handles these commands, that the view *forwards each command onto*.

I could hence have one command object for handling options from the Insert menu, another for the View menu...and so on.  Take a look at this code:

// Container for all the command targets
CTypedPtrArray<CObArray, CCmdTarget*> m_ptrArrayCmdTargets;


// Somewhere in the initialisation of this view
m_ptrArrayCmdTargets.Add(new CInsertMenuCommandTarget());
m_ptrArrayCmdTargets.Add(new CViewMenuCommandTarget());
// etc

where CInsertMenuCommandTarget and CViewMenuCommandTarget are both derived from CCmdTarget

BOOL CMyView::OnCmdMsg(UINT command, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)
{
      // First try passing the command to each of our command targets
      for (int i = 0; i < m_ptrArrayCmdTargets.GetCount(); i++)
            if (m_ptrArrayCmdTargets[i]->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
                  return TRUE;
      
      // Was not handled by one of the command targets, pass it to the base class            
      return CFrameWnd::OnCmdMsg(command, nCode, pExtra, pHandlerInfo);
}

What this essentially is achieving is clearer code, I think.  Also the ability to be able to dynamically insert handlers into the command chain, as the article states, is present.

What do you think ?

Thanks.
ASKER CERTIFIED SOLUTION
Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of mrwad99

ASKER

Fair enough.  We seem to have different ideas about how custom command targets can be used, I guess it just boils down to personal choice.

Thanks.

BTW; have you looked at my other open question ?  It is a real stinker...
BTW; have you looked at my other open question ?  It is a real stinker...

If you mean the combo - yes.  Not a clue why.
Don't forget a CWnd is derived from CCmdTarget (that is why I am a little uncertain as to whether you really do need what you are proposing).
Avatar of mrwad99

ASKER

Ta :)