五维思考

学习要加,骄傲要减,机会要乘,懒惰要除。 http://www.5dthink.cn

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
看似一个简单的功能需求,其实很多初学者处理不好的,很多朋友会这么写:

//父窗体是是frmParent,子窗体是frmChildA
//在父窗体中打开子窗体 
frmChildA child = new frmChildA();
child.MdiParent = this;
child.Show();


//子窗体调父窗体方法:
//错误的调用!!!!!!!!
(this.MdiParent as frmParent).ParentFoo();

知道错在那里吗?错在强依赖!如果父窗体与子窗体在同一个模块内看似没有错,因为这种反向引用在同一个模块内是可行的,但程序不能这么写,你把它写死了!固化了!假设我们的项目不断在扩展,需要将父窗体与子窗体分开在不同的模块,这段代码就完了!因为父窗体模块必须引用子窗体模块,而子窗体需要用到frmParent的类,又要引用父窗体的模块!这时构成了双向引用,编译不能通过,所以讲程序写死了!


有什么办法解除这种依赖关系呢?办法是有的,就是使用接口解除依赖关系!


我们把程序改下:
/// <summary> 
/// 主窗体接口 
/// </summary> 
public interface IMdiParent
{
   void ParentFoo();
}

/// <summary> 
/// 子窗体接口 
/// </summary> 
public interface IMyChildForm
{
   void Foo();
}


主窗体的代码:
/// <summary> 
/// 主窗体,实现IMdiParent接口 
/// </summary> 
public partial class frmParent : Form, IMdiParent
{
   public frmParent()
   {
      InitializeComponent();
   }
   
   private void form1ToolStripMenuItem_Click(object sender, EventArgs e)
   {
      //打开子窗体 
      frmChildA child = new frmChildA();
      child.MdiParent = this;
      child.Show();
   }
   
   private void menuCallFoo_Click(object sender, EventArgs e)
   {
      //调用子窗体的Foo()方法 
      Form activedChild = this.ActiveMdiChild;
      if ((activedChild != null) && (activedChild is IMyChildForm))
         (activedChild as IMyChildForm).Foo();
   }
   
   #region IMdiParent 成员
   
   public void ParentFoo()
   {
      MessageBox.Show("调用" this.GetType().FullName ".ParentFoo()方法!");
   }
   
   #endregion
}

子窗体的代码:
/// <summary> 
/// 子窗体,实现IMyChildForm接口 
/// </summary> 
public partial class frmChildA : Form, IMyChildForm
{
   public frmChildA()
   {
      InitializeComponent();
   }
   
   #region IMyChildForm 成员
   
   public void Foo()
   {
      MessageBox.Show("调用" this.GetType().FullName ".Foo()方法!");
   }
   
   #endregion
   
   private void btnParentFoo_Click(object sender, EventArgs e)
   {
      //调用父窗体的ParentFoo()方法 
      if ((this.MdiParent != null) && (this.MdiParent is IMdiParent))
      (this.MdiParent as IMdiParent).ParentFoo();
   }
   
   private void btnErrCall_Click(object sender, EventArgs e)
   {
      //错误的调用 
      (this.MdiParent as frmParent).ParentFoo();
   }



实现思路:
frmParent窗体所在的模块依赖frmChildA所在模块,而frmChildA只依赖IMdiParent接口,这正是《敏捷软件开发》中所讲的依赖倒置原则。最后,我们把IMdiParent接口部署在一个Common模块内,实际上frmParent与frmChildA只需要依赖Common模块。

Source Code for VS2008:
posted on 2015-03-07 09:05  五维思考  阅读(2181)  评论(0编辑  收藏  举报

QQ群:1. 全栈码农【346906288】2. VBA/VSTO【2660245】