我已经回顾了这个优秀的answer,但我仍感到困惑。最终我将有10个方法都表现相似。以下是我已经写过的三个例子:
void CChristianLifeMinistryEditorDlg::OnSwapWithChairmanAssignment(UINT nID)
{
// We need to locate the name for this assignment
auto iter = m_mapSwapAssignments.find(nID);
if (iter != m_mapSwapAssignments.end())
{
// We found it
CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
CString strExistingName = _T(""), strReplacementName = _T("");
GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);
CString strPrompt = _T("");
strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
m_pEntry->GetMeetingDateAsString(),
(LPCTSTR)strExistingName,
pReplacement->GetMeetingDateAsString(),
(LPCTSTR)pReplacement->GetChairman());
if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
{
strReplacementName = pReplacement->GetChairman();
pReplacement->SetChairman(strExistingName);
SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
SetModified(true);
}
}
}
void CChristianLifeMinistryEditorDlg::OnSwapWithOpenPrayerAssignment(UINT nID)
{
// We need to locate the name for this assignment
auto iter = m_mapSwapAssignments.find(nID);
if (iter != m_mapSwapAssignments.end())
{
// We found it
CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
CString strExistingName = _T(""), strReplacementName = _T("");
GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);
CString strPrompt = _T("");
strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
m_pEntry->GetMeetingDateAsString(),
(LPCTSTR)strExistingName,
pReplacement->GetMeetingDateAsString(),
(LPCTSTR)pReplacement->GetOpenPrayer());
if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
{
strReplacementName = pReplacement->GetOpenPrayer();
pReplacement->SetOpenPrayer(strExistingName);
SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
SetModified(true);
}
}
}
void CChristianLifeMinistryEditorDlg::OnSwapWithClosePrayerAssignment(UINT nID)
{
// We need to locate the name for this assignment
auto iter = m_mapSwapAssignments.find(nID);
if (iter != m_mapSwapAssignments.end())
{
// We found it
CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
CString strExistingName = _T(""), strReplacementName = _T("");
GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);
CString strPrompt = _T("");
strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
m_pEntry->GetMeetingDateAsString(),
(LPCTSTR)strExistingName,
pReplacement->GetMeetingDateAsString(),
(LPCTSTR)pReplacement->GetClosePrayer());
if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
{
strReplacementName = pReplacement->GetClosePrayer();
pReplacement->SetClosePrayer(strExistingName);
SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
SetModified(true);
}
}
}
我想将每个事件处理程序中的代码编码到方法中。
GetChairman
SetChairman
GetOpenPrayer
SetOpenPrayer
GetClosePrayer
SetClosePrayer
我试过这个:
void CChristianLifeMinistryEditorDlg::SwapAssignments(UINT nID, CString(*GetExistingName), void(*SetReplacementName)(CString))
{
// We need to locate the name for this assignment
auto iter = m_mapSwapAssignments.find(nID);
if (iter != m_mapSwapAssignments.end())
{
// We found it
CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
CString strExistingName = _T(""), strReplacementName = _T("");
GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);
CString strPrompt = _T("");
strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
m_pEntry->GetMeetingDateAsString(),
(LPCTSTR)strExistingName,
pReplacement->GetMeetingDateAsString(),
(LPCTSTR)pReplacement->(*GetExistingName));
if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
{
strReplacementName = pReplacement->(*GetExistingName);
pReplacement->(*SetReplacementName)(strExistingName);
SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
SetModified(true);
}
}
}
我遇到构建错误:
如何将这些方法作为参数传递?
我看到我希望可以使用的另一个answer,但问题是被调用的方法是一个对象的成员。所以它不会允许它。
目前我已实施了几项功能:
CString CChristianLifeMinistryEntry::GetName(SwapAssignment eAssignment)
{
switch (eAssignment)
{
case SwapAssignment::Chairman:
return GetChairman();
case SwapAssignment::Counsellor1:
return GetAuxiliaryCounsellor1();
case SwapAssignment::Counsellor2:
return GetAuxiliaryCounsellor2();
case SwapAssignment::OpenPrayer:
return GetOpenPrayer();
case SwapAssignment::Treasures1:
return GetTreasures1();
case SwapAssignment::Treasures2:
return GetTreasures2();
case SwapAssignment::Living1:
return GetLiving1();
case SwapAssignment::Living2:
return GetLiving2();
case SwapAssignment::ConductorCBS:
return GetCBSConductor();
case SwapAssignment::ReaderCBS:
return GetCBSReader();
case SwapAssignment::ClosePrayer:
return GetClosePrayer();
}
return _T("");
}
// AJT v18.1.6
void CChristianLifeMinistryEntry::SetName(CString strName, SwapAssignment eAssignment)
{
switch (eAssignment)
{
case SwapAssignment::Chairman:
SetChairman(strName);
break;
case SwapAssignment::Counsellor1:
SetAuxiliaryCounsellor1(strName);
break;
case SwapAssignment::Counsellor2:
SetAuxiliaryCounsellor2(strName);
break;
case SwapAssignment::OpenPrayer:
SetOpenPrayer(strName);
break;
case SwapAssignment::Treasures1:
SetTreasures1(strName);
break;
case SwapAssignment::Treasures2:
SetTreasures2(strName);
break;
case SwapAssignment::Living1:
SetLiving1(strName);
break;
case SwapAssignment::Living2:
SetLiving2(strName);
break;
case SwapAssignment::ConductorCBS:
SetCBSConductor(strName);
break;
case SwapAssignment::ReaderCBS:
SetCBSReader(strName);
break;
case SwapAssignment::ClosePrayer:
SetClosePrayer(strName);
break;
}
}
然后我将我提到的代码稍微调整一下,移动到一个新方法中:
// AJT v18.1.6
void CChristianLifeMinistryEditorDlg::SwapAssignments(UINT nID, SwapAssignment eAssignment)
{
// We need to locate the name for this assignment
auto iter = m_mapSwapAssignments.find(nID);
if (iter != m_mapSwapAssignments.end())
{
// We found it
CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
CString strExistingName = _T(""), strReplacementName = _T("");
GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);
CString strPrompt = _T("");
strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
m_pEntry->GetMeetingDateAsString(),
(LPCTSTR)strExistingName,
pReplacement->GetMeetingDateAsString(),
(LPCTSTR)pReplacement->GetName(eAssignment));
if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
{
strReplacementName = pReplacement->GetName(eAssignment);
pReplacement->SetName(strExistingName, eAssignment);
if (pReplacement == m_pEntry) // Swapping assignments on same meeting!
SetDlgItemText(IDC_COMBO_OCLM_CBS_READER, strExistingName);
SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
SetModified(true);
}
}
}
所以现在我的11个处理程序看起来与此类似:
// AJT v18.1.6
void CChristianLifeMinistryEditorDlg::OnSwapWithCBSReaderAssignment(UINT nID)
{
SwapAssignments(nID, SwapAssignment::ReaderCBS);
}
有效。但我看到我的问题中添加了一条新评论,并附有链接,所以我会看看我是否可以到达任何地方。
答案 0 :(得分:1)
因此,让我们分阶段重构代码。
第1阶段:
首先,在通用函数OnSwapWith
template<typename Function>
void CChristianLifeMinistryEditorDlg::OnSwapWith(Function && function,
UINT nID)
{
// We need to locate the name for this assignment
auto iter = m_mapSwapAssignments.find(nID);
if (iter != m_mapSwapAssignments.end())
{
// We found it
CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
CString strExistingName = _T(""), strReplacementName = _T("");
GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);
CString strPrompt = _T("");
strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
m_pEntry->GetMeetingDateAsString(),
(LPCTSTR)strExistingName,
pReplacement->GetMeetingDateAsString(),
(LPCTSTR)pReplacement->GetChairman());
if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
{
function();
SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
SetModified(true);
}
}
}
void CChristianLifeMinistryEditorDlg::OnSwapWithChairmanAssignment(UINT nID)
{
auto ChairmanAssignment = [&]() // capture by reference (i.e. &)
{
strReplacementName = pReplacement->GetChairman();
pReplacement->SetChairman(strExistingName);
};
CChristianLifeMinistryEditorDlg::OnSwapWith(ChairmanAssignment, nID);
}
void CChristianLifeMinistryEditorDlg::OnSwapWithOpenPrayerAssignment(UINT nID)
{
auto OpenPrayerAssignment = [&]() // capture by reference (i.e. &)
{
strReplacementName = pReplacement->GetOpenPrayer();
pReplacement->SetOpenPrayer(strExistingName);
};
CChristianLifeMinistryEditorDlg::OnSwapWith(OpenPrayerAssignment, nID);
}
void CChristianLifeMinistryEditorDlg::OnSwapWithClosePrayerAssignment(UINT nID)
{
auto ClosePrayerAssignment = [&]() // capture by reference (i.e. &)
{
strReplacementName = pReplacement->GetClosePrayer();
pReplacement->SetClosePrayer(strExistingName);
};
CChristianLifeMinistryEditorDlg::OnSwapWith(ClosePrayerAssignment, nID);
}
// and similarly other functions can be defined
在重构之后,我们至少减少了一级冗余。
在这次重构中,我们通过引用在行中捕获了所有内容:
auto ChairmanAssignment = [&]() {};
通过引用捕获时,所有内容都被捕获,例如this
指针
这就是为什么这句话有效:
strReplacementName = pReplacement->GetChairman();
它扩展为:
this->strReplacementName = pReplacement->GetChairman();
第2阶段: 理解你所使用的基本上只是一些通用的 getters 和 setters 。
所以让我们进一步重构:
// instead of passing one function, we will pass two : getter and setter
template<typename GetterFunction,
typename SetterFunction>
void CChristianLifeMinistryEditorDlg::OnSwapWith(GetterFunction && getter,
SetterFunction && setter,
UINT nID)
{
...
if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
{
strReplacementName = getter(pReplacement);
setter(pReplacement, strExistingName);
SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
SetModified(true);
}
...
}
和来电方
void CChristianLifeMinistryEditorDlg::OnSwapWithChairmanAssignment(UINT nID)
{
auto getter = [](CChristianLifeMinistryEntry * pReplacement)
{ // remove the captures now, since we are getting the state with the pointer
return pReplacement->GetChairman();
};
auto setter = [](CChristianLifeMinistryEntry * pReplacement,
CString const & strExistingName)
{
pReplacement->SetChairman(strExistingName);
};
CChristianLifeMinistryEditorDlg::OnSwapWith(getter, setter, nID);
}
11个菜单事件处理程序看起来像:
void CChristianLifeMinistryEditorDlg::OnSwapWithChairmanAssignment(UINT nID)
{
auto getter = [](CChristianLifeMinistryEntry * pReplacement)
{
return pReplacement->GetChairman();
};
auto setter = [](CChristianLifeMinistryEntry * pReplacement,
CString & strExistingName)
{
pReplacement->SetChairman(strExistingName);
};
CChristianLifeMinistryEditorDlg::OnSwapWith(getter, setter,
nID, IDC_COMBO_OCLM_CHAIRMAN);
}
模板化功能现在看起来像:
template<typename GetterFunction, typename SetterFunction>
void CChristianLifeMinistryEditorDlg::OnSwapWith(GetterFunction && getter,
SetterFunction && setter,
UINT nID,
UINT nReplacementCtrlID)
{
// We need to locate the name for this assignment
auto iter = m_mapSwapAssignments.find(nID);
if (iter != m_mapSwapAssignments.end())
{
// We found it
CChristianLifeMinistryEntry *pReplacement = m_mapSwapAssignments[nID];
CString strExistingName = _T(""), strReplacementName = _T("");
GetDlgItemText(m_iSwapAssignmentSourceID, strExistingName);
CString strPrompt = _T("");
strPrompt.Format(_T("Swap assignments:\n\n%s - %s\n%s - %s\n\nPlease confirm."),
m_pEntry->GetMeetingDateAsString(),
(LPCTSTR)strExistingName,
pReplacement->GetMeetingDateAsString(),
(LPCTSTR)getter(pReplacement));
if (AfxMessageBox(strPrompt, MB_ICONQUESTION | MB_YESNO) == IDYES)
{
strReplacementName = getter(pReplacement);
setter(pReplacement, strExistingName);
if (pReplacement == m_pEntry) // Swapping assignments on same meeting!
SetDlgItemText(nReplacementCtrlID, strExistingName);
SetDlgItemText(m_iSwapAssignmentSourceID, strReplacementName);
SetModified(true);
}
}
}