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
LVL 19
mrwad99Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

AndyAinscowFreelance programmer / ConsultantCommented:
<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.
AndyAinscowFreelance programmer / ConsultantCommented:
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)
mrwad99Author Commented:
Andy

I have not forgotten this Q.  I will re-read the article and then come back.  Thanks.
HTML5 and CSS3 Fundamentals

Build a website from the ground up by first learning the fundamentals of HTML5 and CSS3, the two popular programming languages used to present content online. HTML deals with fonts, colors, graphics, and hyperlinks, while CSS describes how HTML elements are to be displayed.

AndyAinscowFreelance programmer / ConsultantCommented:
No probs.
mrwad99Author Commented:
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.
AndyAinscowFreelance programmer / ConsultantCommented:
Two points spring to mind about the initial scenario (100 options on new menu).
Are there really 100 options OR 10 options for 10 different (eg. view) types.  That would only require 10 handlers not 100.

Secondly ON_COMMAND_RANGE and the equivalent update handler.  (You now have one message map handler , unfortunately one big function as well).


Then your piece of code.
That is essentially what MFC does, just that doc/view/frame... are all derived from a CCmdTarget.
So it should work BUT you *may* need to have something to prevent the CInsertMenuCommandTarget reacting if it is not with the focus for example.  (MFC already takes care of that)

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
mrwad99Author Commented:
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...
AndyAinscowFreelance programmer / ConsultantCommented:
BTW; have you looked at my other open question ?  It is a real stinker...

If you mean the combo - yes.  Not a clue why.
AndyAinscowFreelance programmer / ConsultantCommented:
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).
mrwad99Author Commented:
Ta :)
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
System Programming

From novice to tech pro — start learning today.