我有一个名为IDataIO的接口:
public interface IDataIO
{
event DataReceivedEvent DataReceived;
//.....more events,methods and properties
}
我还有多个实现此接口的类,即UdpIO
,TcpIO
,SerialIO
。
现在,我有一个IO
类,允许我在不同的输入/输出硬件之间切换。此类的每个实例都有CurrentIODevice
属性,可以是SerialIO
,UdpIO
或TcpIO
之一。分配此属性后,我会将一个或多个处理程序附加到DataReceivedEvent
,以便在收到传入数据时通知我的GUI,以及需要通知的其他类。
public class IO
{
IDataIO CurrentIODevice;
public IO()
{
SerialIO serial = new SerialIO();
TcpIO tcp = new TcpIO();
UdpIO udp = new UdpIO();
CurrentIODevice = serial;
}
}
我还有一个IOManager
类,它包含多个IO
个对象。
public class IOManager
{
List<IO> Ports = new List<IO>();
public IOManager()
{
Ports.Add(new IO());
Ports.Add(new IO());
}
Ports[0].CurrentIODevice = serial;
Ports[0].CurrentIODevice.DataReceivedHandler += MyGuiUpdate;
Ports[0].CurrentIODevice.DataReceivedHandler += MyDataProcessing;
}
我的担忧(不是问题atm)是我如何在运行时在不同的IDataIO接口之间进行更改。
在运行时执行以下语句的影响是什么:
//i know this is illegal but just to demonstrate
IOManager.Ports[0].CurrentIODevice = tcp;
事件处理程序是否仍在运行(并且正确)?
我是否需要在分配CurrentIODevice之前取消分配事件,然后再重新分配处理程序?如果是这种情况,我可以看到这种方法变得非常混乱,所以如果有人对这个问题有更好的解决方法,我会全力以赴:)
答案 0 :(得分:15)
不,您的处理程序将无法正常工作,因为它们已附加到旧对象上。接口提供了......对象的接口,将其视为一种契约,但它们本身并不是一个不同的对象。
如果你需要在界面的不同实现之间切换(在运行时)并且为了保持所有处理程序的工作,你必须为接口本身提供相同的对象引用,strategy pattern种类(或多或少) )。
在您的情况下,您可以在IDataIO
对象中实现DataIO
接口。它将公开一个属性(或一种方法,我认为它的意图更清楚)在该接口的不同实现之间切换(串行,TCP或其他)。它将是唯一一个将事件处理程序附加到该接口的对象(当具体实现将发生变化时,它将删除处理程序)。该对象的用户将始终看到它,无论它是否正在使用它的具体实现。
这是解释这个概念的一个小例子。通用接口是这样的:
interface IDataIO
{
void Write(byte[] data);
byte[] Read();
event EventHandler DataReceived;
}
这是IDataIO的具体实现,其他类将直接使用此类:
sealed class DataIO : IDataIO
{
public void SetChannel(IDataIO concreteChannel)
{
if (_concreteChannel != null)
_concreteChannel.DataReceived -= OnDataReceived;
_concreteChannel = concreteChannel;
_concreteChannel.DataReceived += OnDataReceived;
}
public void Write(byte[] data)
{
_concreteChannel.Write(data);
}
public byte[] Read()
{
return _concreteChannel.Read();
}
public event EventHandler DataReceived;
private IDataIO _concreteChannel;
private void OnDataReceived(object sender, EventArgs e)
{
EventHandler dataReceived = DataReceived;
if (dataReceived != null)
dataReceived(this, e);
}
}
最后一些测试代码:
class Test
{
public Test()
{
_channel = new TcpIO();
_channel.DataReceived += OnDataReceived;
}
public void SetChannel(IDataIO channel)
{
_channel.SetChannel(channel);
// Nothing will change for this "user" of DataIO
// but now the channel used for transport will be
// the one defined here
}
private void OnDataReceived(object sender, EventArgs e)
{
// You can use this
byte[] data = ((IDataIO)sender).Read();
// Or this, the sender is always the concrete
// implementation that abstracts the strategy in use
data = _channel.Read();
}
private DataIO _channel;
}
答案 1 :(得分:2)
显然你应该考虑strategy pattern。我将首先发布代码并稍后解释:
public interface IDataIO
{
event DataReceivedEvent DataReceived;
//this the new added method that each IO type should implement.
void SetStrategy();
}
public class SerialIO : IDataIO
{
public void SetStrategy()
{
//put the code that related to the Serial IO.
this.DataReceivedHandler += MyGuiUpdate;
this.DataReceivedHandler += MyDataProcessing;
}
}
public class TcpIO : IDataIO
{
public void SetStrategy()
{
//put the code that related to the Tcp IO.
//I will not implement it because it is a demo.
}
}
public class UdpIO : IDataIO
{
public void SetStrategy()
{
//put the code that related to the Udp IO.
//I will not implement it because it is a demo.
}
}
public class IO
{
IDataIO port = new IDataIO();
public void SetIOType(IDataIO ioType)
{
this.port = ioType;
port.SetStrategy();
}
}
public class IOManager
{
List<IO> ports = new List<IO>();
SerialIO serial = new SerialIO();
TcpIO tcp = new TcpIO();
ports[0].SetIOType(serial);
ports[1].SetIOType(tcp);
}
接口IDataIO定义了所有IO类型应实现的基础知识。
从IDataIO派生的SerialIO,TcpIO,UdpIO类实现了SetStrategy()方法,以满足他们自己的需要。
IO类拥有一个字段(命名端口)是指IDataIO类型,通过调用IO中定义的方法SetIOType(),可以在运行时将该字段设置为某种IO类型 类。一旦调用了这个方法,我们就知道'port'字段所指的类型,和 然后调用SetStrategy()方法,它将在其中一个IO类中运行覆盖方法。
IOManager类是客户端。当它需要某种IO类型时,比如SerialIO,它只需要新建一个IO类并通过传递一个SerialIO类实例调用SetIOType()方法,并且所有与SerialIO类型相关的逻辑都将自动设置。
希望我的描述可以帮到你。