我正在尝试更多地使用接口,而且我经常发现自己将事件放入接口。这感觉很奇怪,因为我要离开实施者,知道何时在实施过程中提出这些事件。
例如,我有一个ILevellable接口,它只是声明一个对象应该有xp,一个级别和一个最大级别,以及一些修改这些值的方法。引用ILevellable的类可能想知道它何时升级,所以我为OnLevelUp添加了一个Action ......但是实现可能不会将它放在正确的位置。
public interface ILevellable
{
int Level { get; }
int MaxLevel { get; }
int XP { get; }
event Action<bool> OnXPChanged;
event Action<ILevellable> OnLevelUp;
event Action OnMaxLevelReached;
void LevelUp(int newLevel);
}
我是否应该相信实现此接口的用户将知道在哪里实现此功能?我不会假设。特别是因为某些事件可能有参数,用户可能也不知道应该代表什么。
我感谢任何指导!我是新手,像这样工作。
谢谢!
在接口中定义事件很好。然而,将'sender'和'event args'都传递给事件是符合惯例的。 TypedEventHandler是一种简单的方法。例如:
using Windows.Foundation;
public struct LevellableChange {
public LevellableChange( int dl, int dxp)
{
this.ChangeInLevel = dl;
this.ChangeInXP = dxp;
}
int ChangeInLevel { get; }
int ChangeInXP {get;}
}
public interface ILevellable
{
int Level { get; }
int MaxLevel { get; }
int XP { get; }
event TypedEventHandler< ILevellable, LevellableChange> Changed;
}
然后实现它们的标准方法是这样的:
public class Levellable: ILevellable
{
public event TypedEventHandler<ILevellable, LevellableChange> Changed;
public int Level {
get {
return this._level;
}
private set {
if (value != this._level) {
int oldLevel = this._level;
this._level = value;
this.Changed?.Invoke(this, new LevellableChange(value - oldLevel, 0));
}
}
}
private int _level;
// similar for XP.
}
另一个注释,让一个实现INotifyPropertyChanged的类很有用,然后养成从中派生的习惯。与Visual Studio中的代码段一起使事情变得更加容易。确实,对于上面的示例,INotifyPropertyChanged是不够的,因为它不会给前一个值提供更改。
首先,您的接口定义中没有委托类型,而是事件。检查Jon Skeet的this answer,看看代表和事件之间的区别。在说你的界面中有事件完全没问题之后,甚至.Net都会这样做,例如考虑着名的INotifyPropertyChanged界面。它只是定义了一个事件......
其次:
我是否应该相信实现此接口的用户将知道在哪里实现此功能?
当您定义一个接口时,您实际上并不关心实现者和消费者,因此,对于看到您的合同定义的消费者而言,知道他/她可以挂起名为OnLevelUp
的事件是有用的。假设我确实正在使用你的界面,我不知道你是怎么或何时触发OnLevelUp
事件,我不应该真的关心,因为你已经给了那个非常语义和有意义的名字,所以我几乎可以肯定它将在ILevellable
的Level属性增加时触发。