• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 377
  • Last Modified:

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
0
mrwad99
Asked:
mrwad99
  • 6
  • 4
1 Solution
 
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.
0
 
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)
0
 
mrwad99Author Commented:
Andy

I have not forgotten this Q.  I will re-read the article and then come back.  Thanks.
0
Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

 
AndyAinscowFreelance programmer / ConsultantCommented:
No probs.
0
 
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.
0
 
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)
0
 
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...
0
 
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.
0
 
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).
0
 
mrwad99Author Commented:
Ta :)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

  • 6
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now