第14章 对象间的协作与信息交换
【简介】:面向对象的程序 = 对象 + 对象之间的相互协作关系。在任何一个面向对象程序开发过程中,设计好对象之间的协作关系与信息交换方式都属于开发的核心任务,本章主要介绍了“一对一”对象之间、“一对多”对象之间的相互协作与信息交换的基本方式等。
第1节 对象间信息交换的基本方式
1、 对象协作的本质:就是对象间信息交换的问题,体现为对象之间的相互访问,即设置对象属性与调用对象方法。
2、对象间信息交换的方法:获取要访问对象的引用,设置对象属性与调用对象方法。
3、案例:主窗体向从窗体传递信息。
主窗体代码:
namespace MultiFormProgram1
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
frm = new frmOther(); //创建从窗体对象
frm.Show();//显示从窗体
}
private frmOther frm = null; //◆定义私有字段,用于引用从窗体对象,很重要哟!
private void btnSend_Click(object sender, EventArgs e)
{
frm.SetValue(txtUserInput.Text); //◆调用从窗体方法,传递参数值。
}
}
}
从窗体代码:
namespace MultiFormProgram1 { public partial class frmOther : Form { public frmOther() { InitializeComponent(); } //对从窗体的Label设置值 public void SetValue(string s) { lblInfo.Text = "老大说:" + s; } } }
4、思考:
A、除了用方法参数传递信息外,还有何方式?
【答】:当然是对象的属性这种更直接的方式。
B、如果需要在主窗体与从窗体双向传递怎么办?
【答】:建立双向关联,即每个对象都拥有对方的引用。即主窗体有一个私有字段引用从窗体,从窗体也有一个私有字段引用主窗体。
C、如何有很多对象都需要相互传递信息,用此方法行不行吗?
【答】:行,但不够好。这时用委托来实现。因此,此技术最适合的场所是对象的一对一通信且只有很少的对象。
第二节 多对象协作与信息交换--广播信息
1、原理:利用委托类型的变量可以引用多个方法构成的列表(委托调用列表)。
2、案例:利用委托“广而告之”
主窗体代码:
namespace UseDelegate { public partial class frmMain : Form { public frmMain() { InitializeComponent(); } private Action<int> ReceiverMethods; //定义委托变量,用于引用方法 private void btnNewForm_Click(object sender, EventArgs e) { NewForm(); } private void NewForm() { frmOther frm = new frmOther(); ReceiverMethods += frm.ShowCounter; //挂接从窗口的方法 frm.Show(); } private int counter = 0;//计数器 private void btnClickMe_Click(object sender, EventArgs e) { counter++; if (ReceiverMethods != null) ReceiverMethods(counter); //方法调用 } } }
从窗口代码:
namespace UseDelegate { public partial class frmOther : Form { public frmOther() { InitializeComponent(); } public void ShowCounter(int counter) //显示消息 { lblInfo.Text = counter.ToString(); } } }
3、思考:
A、利于事件是否也能实现“广播消息”?
【答】:可以,因为事件的本质就是多路委托。思路:主窗体定义一个事件,从窗体对象响应之。
B、能否通知的是不同类型的对象?
【答】:可以,只要不同类型的对象的实例方法符合委托所确定的方法签名即可。
C、它实现的原理是什么?
【答】:充分利用委托的"多路"特性,实现了消息的传播(具体是通过方法参数传递的)。
第三节 多对象协作与信息交换--一个对象“监控”多个对象
1、本节介绍的是“反方向”的信息传播问题,即多个对象向一个对象发送信息,可形象地比喻成:一个对象监控多个对象。
2、案例:从窗体向主窗体传递信息:
主窗口代码:
namespace ButtonCounterForMultiFormUseDelegate
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
}
private int counter = 0;
/// <summary>
/// 显示累计按钮单击次数的结果
/// </summary>
private void ShowCounter()
{
counter++;
lblInfo.Text = counter.ToString();
}
private void btnShowOtherForm_Click(object sender, EventArgs e)
{
frmOther frm = new frmOther();
//◆◆将主窗体的方法“挂接”到从窗体对象上
frm.CallBackMethod = this.ShowCounter;
//在屏幕上显示从窗体
frm.Show();
}
}
}
从窗体代码:
namespace ButtonCounterForMultiFormUseDelegate
{
public partial class frmOther : Form
{
public frmOther()
{
InitializeComponent();
}
public Action CallBackMethod = null; //◆定义委托变量,用于引用方法
private void btnClickMe_Click(object sender, EventArgs e)
{
//回调主窗体的方法,显示按钮计数
if (CallBackMethod != null)
CallBackMethod(); //◆回调主窗体的方法
}
}
}
3、思考:
A、为什么在从窗体中定义委托变量,而不是在主窗体中定义?
【答】:因为实际需求是:当点击从窗体的按钮时,回调主窗体的方法来显示次数。
B、能否可以用事件机制实现?
【答】:可以。
C、除了利用委托或事件实现外,有无别的方法?
【答】:有的,第一种就是利用组合关系,即让从窗体对象持有主窗体对象的引用,即第一节介绍的方法。
第二种方式从窗体利用静态方法主动通知主窗体,这种方法本质上是定义了“全局”的字段与方法。
用委托实现,可以不需要相互执有对方的引用,从而减少了对象之间的耦合度。