c#重构两个几乎相同的方法
c# Refactoring two nearly identical Methods
重构固然好,但有时要弄清楚如何重构以及是否真的可以重构并不是那么容易!
我有很多几乎相同的方法 - 我可以重构它们,但重构的一部分超出了我的逻辑。
这里有两个未重构的方法:
private void projectToolStripMenuItem_Click(object sender, EventArgs e)
{
if (projectToolStripMenuItem.Checked)
{
projectToolStripMenuItem.Checked = false;
if (!projectForm.IsDisposed) projectForm.Hide();
}
else
{
if (projectForm.IsDisposed)
projectForm = new frmProject();
projectForm.Show(dockPanel, DockState.DockRight);
projectToolStripMenuItem.Checked = true;
}
}
private void logginToolStripMenuItem_Click(object sender, EventArgs e)
{
if (logginToolStripMenuItem.Checked)
{
logginToolStripMenuItem.Checked = false;
if (!outputForm.IsDisposed) outputForm.Hide();
}
else
{
if (outputForm.IsDisposed)
outputForm = new frmOutput();
outputForm.Show(dockPanel, DockState.DockBottom);
logginToolStripMenuItem.Checked = true;
}
}
通过重构,我会得到一个像这样的方法,以前未重构的方法会调用
private void refactoredMethod(TooStripMenuItem menuItem, DockContent frmName)
{
if (menuItem.Checked)
{
menuItem.Checked = false;
if (!frmName.IsDisposed) frmName.Hide();
}
else
{
if (frmName.IsDisposed)
frmName= new frmProject(); // Still Problematic
frmName.Show(dockPanel, DockState.DockRight);
menuItem.Checked = true;
}
}
那么我们有一个几乎完全重构的方法 - 有一个问题,我怎么知道我想从 frmName
变量中实例化哪个 form
?
将工厂传递给方法,如下所示:
private void RefactoredMethod(..., Func<TypeOfItemToCreate> creator)
{
...
if (frmName.IsDisposed)
frmName = creator();
}
唯一的要求是您创建的两个 classes 都需要有一些共同的接口或基础 class。
您可以使方法通用并利用 new()
通用约束。
private TForm refactoredMethod<TForm>(TooStripMenuItem menuItem, TForm frmName) where TForm : Form, new()
{
if (menuItem.Checked)
{
menuItem.Checked = false;
if (!frmName.IsDisposed) frmName.Hide();
}
else
{
if (frmName.IsDisposed)
frmName= new TForm();
frmName.Show(dockPanel, DockState.DockRight);
menuItem.Checked = true;
}
return frmName;
}
所以你可以称它为
projectForm = refactoredMethod<frmProject>(projectToolStripMenuItem, projectForm);
一个限制是您的表单应该有一个 public 无参数构造函数。如果你有一个带有参数化构造函数的 Form
,你可以将 Func<TForm>
传递给你的方法,它充当工厂方法。
我看到已经有答案了,还想再写点东西。我相信重构比你在这里描述的要多得多。
一件事是更改函数的名称,一件事是将代码放入单独的函数中。
还要记住,没有适当的单元测试就没有适当的重构。
在您的示例中,您混合使用了高级函数和低级函数
(将 false 更改为 true,创建对象等),函数本身也不是自我描述的。
所以在重构方面还有很多工作要做:
void hideForm(TForm form){
if(!form.IsDisposed){
form.Hide();
}
}
void showFormInDockPanel<TForm>(TForm form, DockPanel dockPanel){
if(form.IsDisposed){
form = new TForm();
}
form.Show(dockPanel, DockState.DockRight);
}
void toggleFormAndMenuItem<TForm>(TForm form, TooStripMenuItem menuItem){
if(menuItem.checked){
hideForm(form);
}
else {
showFormInDockPanel<TForm>(form, dockPanel);
}
menuItem.checked = !menuItem.checked;
}
private void projectToolStripMenuItem_Click(object sender, EventArgs e){
toggleFormAndMenuItem<frmProject>(projectToolStripMenuItem, projectForm);
}
重构固然好,但有时要弄清楚如何重构以及是否真的可以重构并不是那么容易!
我有很多几乎相同的方法 - 我可以重构它们,但重构的一部分超出了我的逻辑。
这里有两个未重构的方法:
private void projectToolStripMenuItem_Click(object sender, EventArgs e)
{
if (projectToolStripMenuItem.Checked)
{
projectToolStripMenuItem.Checked = false;
if (!projectForm.IsDisposed) projectForm.Hide();
}
else
{
if (projectForm.IsDisposed)
projectForm = new frmProject();
projectForm.Show(dockPanel, DockState.DockRight);
projectToolStripMenuItem.Checked = true;
}
}
private void logginToolStripMenuItem_Click(object sender, EventArgs e)
{
if (logginToolStripMenuItem.Checked)
{
logginToolStripMenuItem.Checked = false;
if (!outputForm.IsDisposed) outputForm.Hide();
}
else
{
if (outputForm.IsDisposed)
outputForm = new frmOutput();
outputForm.Show(dockPanel, DockState.DockBottom);
logginToolStripMenuItem.Checked = true;
}
}
通过重构,我会得到一个像这样的方法,以前未重构的方法会调用
private void refactoredMethod(TooStripMenuItem menuItem, DockContent frmName)
{
if (menuItem.Checked)
{
menuItem.Checked = false;
if (!frmName.IsDisposed) frmName.Hide();
}
else
{
if (frmName.IsDisposed)
frmName= new frmProject(); // Still Problematic
frmName.Show(dockPanel, DockState.DockRight);
menuItem.Checked = true;
}
}
那么我们有一个几乎完全重构的方法 - 有一个问题,我怎么知道我想从 frmName
变量中实例化哪个 form
?
将工厂传递给方法,如下所示:
private void RefactoredMethod(..., Func<TypeOfItemToCreate> creator)
{
...
if (frmName.IsDisposed)
frmName = creator();
}
唯一的要求是您创建的两个 classes 都需要有一些共同的接口或基础 class。
您可以使方法通用并利用 new()
通用约束。
private TForm refactoredMethod<TForm>(TooStripMenuItem menuItem, TForm frmName) where TForm : Form, new()
{
if (menuItem.Checked)
{
menuItem.Checked = false;
if (!frmName.IsDisposed) frmName.Hide();
}
else
{
if (frmName.IsDisposed)
frmName= new TForm();
frmName.Show(dockPanel, DockState.DockRight);
menuItem.Checked = true;
}
return frmName;
}
所以你可以称它为
projectForm = refactoredMethod<frmProject>(projectToolStripMenuItem, projectForm);
一个限制是您的表单应该有一个 public 无参数构造函数。如果你有一个带有参数化构造函数的 Form
,你可以将 Func<TForm>
传递给你的方法,它充当工厂方法。
我看到已经有答案了,还想再写点东西。我相信重构比你在这里描述的要多得多。 一件事是更改函数的名称,一件事是将代码放入单独的函数中。 还要记住,没有适当的单元测试就没有适当的重构。
在您的示例中,您混合使用了高级函数和低级函数 (将 false 更改为 true,创建对象等),函数本身也不是自我描述的。
所以在重构方面还有很多工作要做:
void hideForm(TForm form){
if(!form.IsDisposed){
form.Hide();
}
}
void showFormInDockPanel<TForm>(TForm form, DockPanel dockPanel){
if(form.IsDisposed){
form = new TForm();
}
form.Show(dockPanel, DockState.DockRight);
}
void toggleFormAndMenuItem<TForm>(TForm form, TooStripMenuItem menuItem){
if(menuItem.checked){
hideForm(form);
}
else {
showFormInDockPanel<TForm>(form, dockPanel);
}
menuItem.checked = !menuItem.checked;
}
private void projectToolStripMenuItem_Click(object sender, EventArgs e){
toggleFormAndMenuItem<frmProject>(projectToolStripMenuItem, projectForm);
}