一、前言
在开发过程中,我们常常遇见上图这样的需求,比如血量增加时就需要对应更新GUI,或者影响其他的值变化,很多读者可能会按照这样的结构去做。这正是Java式的属性写法,显得很臃肿,如果想要避免修改AddHp方法,同样需要在本类内新建委托。
public class MyClass
{
//生命值
int Hp = 100;
//血量增加
void AddHp(int value)
{
//加血
Hp+=Value;
//更新GUI
UpdateGUI(Hp);
}
}
不过本文是基于C#的,C#引入了属性来简化这样的问题,我们只需要修改Hp的属性值,即可快速的绑定事件,但是这样违反开闭原则,我们一旦新增事件就需要修改源代码。比如我想要同时通知体力恢复速度+10,我就需要在set访问器内继续写新的内容,修改原有代码。
int hp=100;
public int Hp
{
get=>hp;
set
{
hp = value;
UpdateGUI(value);
}
}
二、 引入BindableProperty
笔者曾在Github上看到这样一种方式,感觉十分优雅,具体是谁的项目已经记不清了,开发者将这种形式称为BindableProperty,这样我们一旦修改Hp的值,就会对应执行相应的值变更事件。
public class MyClass
{
//生命值
public var Hp = new BindableProperty<int>(100);
public MyMethod()
{
Hp.Value-=10;//自动更新UpdateGUI
}
public MyClass()
{
Hp.OnValueChanged+=UpdateGUI;
}
}
三、实现 BindableProperty
我们首先需要比较值是否相等,所以要求T类型实现IEqualityComparer泛型接口,整个BindableProperty通过event实现事件列表,并通过属性监听
public class BindableProperty<T> where T :IEqualityComparer<T>
{
//保存真正的值
private T value;
//get时返回真正的值,set时顺便调用值改变事件
protected T Value {
get => value;
set
{
if (!Equals(value,this.value))
{
this.value = value;
OnValueChanged(value);
}
}
}
//用event存储值改变的事件
public event Action<T> OnValueChanged;
//初始化
public BindableProperty(T value)
{
this.value = value;
}
public BindableProperty()
{
this.value =default(T);
}
}
这样我们就能便捷的监听字段的更新了