?
Solved

Chain of responsibility design pattern: query

Posted on 2006-04-21
10
Medium Priority
?
374 Views
Last Modified: 2013-11-20
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
Comment
Question by:mrwad99
  • 6
  • 4
10 Comments
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16524824
<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
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16533353
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
 
LVL 19

Author Comment

by:mrwad99
ID: 16585007
Andy

I have not forgotten this Q.  I will re-read the article and then come back.  Thanks.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16585268
No probs.
0
 
LVL 19

Author Comment

by:mrwad99
ID: 16681824
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
 
LVL 45

Accepted Solution

by:
AndyAinscow earned 500 total points
ID: 16688028
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
 
LVL 19

Author Comment

by:mrwad99
ID: 16698326
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
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16698628
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
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 16699754
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
 
LVL 19

Author Comment

by:mrwad99
ID: 16717004
Ta :)
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Loops Section Overview
Suggested Courses
Course of the Month15 days, 15 hours left to enroll

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question