一、 需求分析
在我们开发的一个项目中,需要自己开发一个安装系统,便于部署特定环境下的产品系统。要求的安装界面如图19-1所示:
图19-3 修改后的设计类图
相比最初的设计,我们仅仅新增加了一个ISetupCommand接口,同时将原来在主窗口类中的安装方法,转移到了各个UserControl对象中,作为ISetupCommand接口方法的实现。
四、 进一步完善
虽然程序结构在引入Command模式后有了很大的改观,然而现有的各个ISetupCommand对象并不能很好地被主窗体对象所调用。在为btnNext和btnPrevious按钮的Click事件实现安装行为时,安装步骤必须是顺次执行的,而如今的设计,并不能体现这样一个顺序关系。唯一的办法,是将这些ISetupCommand对象依次放入一个集合对象中,并提供Next()和Previous()方法,返回正确的对象:
public class SetupUCChain
{
private List m_list;
private int m_step;
private static SetupUCChain m_chain;
private SetupUCChain()
{
m_list = new List();
m_step = 0;
Init();
}
public static SetupUCChain CreateSetupUCChain()
{
if (m_chain == null)
{
return new SetupUCChain();
}
else
{
return m_chain;
}
}
private void Init()
{
m_list.Add(new Step1BodyUC());
m_list.Add(new Step2BodyUC());
m_list.Add(new Step3BodyUC());
m_list.Add(new Step4BodyUC());
m_list.Add(new Step5BodyUC());
m_list.Add(new Step6BodyUC());
m_list.Add(new Step7BodyUC());
}
public ISetupCommand Next()
{
++m_step;
if (m_step {
return (ISetupCommand)m_list[m_step];
}
else
{
throw new IndexOutOfRangeException("Setup is completed.");
}
}
public ISetupCommand Previous()
{
--m_step;
if (m_step >= 0)
{
return (ISetupCommand)m_list[m_step];
}
else
{
throw new IndexOutOfRangeException("No previous step.");
}
}
}
考虑到SetupUCChain对象最多只能实例化一次,因此我在此引入了Singleton模式。
最后,由于在各自的安装方法中,需要将UserControl本身添加到主窗体Pannel控件的子控件中,我们还需要修改ISetupCommand的接口方法,从参数传入Pannel控件对象:
public interface ISetupCommand
{
void ExecuteSetup(Pannel pannel);
}
那么在各个UserControl对象中,需要在原有的安装方法实现中添加如下的代码:
panel.Controls.Add(this);
现在,对于btnPrevious和btnNext按钮的Click事件而言,逻辑就非常简单了:
public class SetupMainForm:System.Windows.Forms.Form
{
private System.Windows.Forms.Panel panBody;
private SetupUCChain m_chain = SetupUCChain.CreateSetupUCChain();
//中间代码略;
private void btnNext_Click(object sender, System.EventArgs e)
{
try
{
m_chain.Next().ExecuteSetup(panBody);
}
catch (IndexOutOfRangeException ex)
{
MessageBox.Show(ex.Message);
}
}
private void btnPrevious_Click(object sender, System.EventArgs e)
{
try
{
m_chain.Previous().ExecuteSetup(panBody);
}
catch (IndexOutOfRangeException ex)
{
MessageBox.Show(ex.Message);
}
}
}
通过引入设计模式,运用职责分离的原理,我们将与安装有关的逻辑剥离出主窗体类定义,使得整个结构清晰简要,职责分明,且因为对可能存在的变化进行了封装,同时也具备了可扩展性,形成了结构之间的松散耦合。这样的完善设计的整个过程虽然会耗费我们项目开发的时间,然而付出的努力并没有付诸东流,改善后的结构才是健壮的、逻辑清楚的,同样也是优雅的设计。