如何用观察者模式观察同一类型的不同属性?
How to observe different attributes of same types with the Observer pattern?
我在 MVC 应用程序中实现了观察者模式,因此 bean 可以侦听模型中的更改。因为我在 Java8,所以我使用 Java.util 的 Observer 和 Observable。这是我编码的部分内容:
import java.util.Observable;
import java.util.Observer;
public class UserBean implements Observer{
private Integer userId;
private String userName;
private String userEmail;
/* getters and setters */
@Override
public void update(Observable o, Object object) {
if(object instanceof Integer)
setUserId((Integer)object);
else if(object instanceof String)
setUserName((String)object);
}
}
public class UserModel extends Observable {
private Integer id;
private String name;
private String email;
/* getters */
public void setId(Integer id){
this.id = id;
setChanged();
notifyObservers(id);
}
public void setName(String name){
this.name = name;
setChanged();
notifyObservers(name);
}
public void setEmail(String email){
this.name = email;
// how can i listen for this change?
/*setChanged();
notifyObservers(email);*/
}
}
我认为实现是正确的,因为在我进行的简单测试中,bean 正确读取了 ID 和名称的更改 class,但我意识到我无法监听更改电子邮件属性,因为在 bean class 中,我使用 'instanceof' 来了解我必须更新哪个值。
有什么方法可以识别哪个变量发生了变化?我应该实现自己的 Observer 和 Observable class 版本而不是使用 Java.Util?
我认为使用第二种解决方案我可以为每个属性定义一个更新方法,但我不知道如何在 Java.
中管理同步过程
update
方法中的第一个参数是 Observable
。那是您的 UserModel
对象发生了变化,因此它包含所有更新的数据。因此,与其使用第二个参数来传递对象的新 value,不如使用它来传递已更改对象的 name (或使用 enum
因为它有点 cleaner).
解决方案可能如下所示:
UserBean:
import java.util.Observable;
import java.util.Observer;
import observer.UserModel.ChangedValue;
public class UserBean implements Observer {
private Integer userId;
private String userName;
private String userEmail;
/* getters and setters */
@Override
public void update(Observable o, Object object) {
if (o instanceof UserModel && object instanceof ChangedValue) {
UserModel userModel = (UserModel) o;
ChangedValue changed = (ChangedValue) object;
switch (changed) {
case EMAIL:
setEmail(userModel.getEmail());
break;
case ID:
setUserId(userModel.getId());
break;
case NAME:
setUserName(userModel.getName());
break;
default:
throw new IllegalStateException("Unexpected ChangedValue type: " + changed);
}
}
}
//...
}
用户模型:
import java.util.Observable;
public class UserModel extends Observable {
public enum ChangedValue {
ID, //
NAME, //
EMAIL, //
//...
}
private Integer id;
private String name;
private String email;
//...
public void setId(Integer id) {
this.id = id;
setChanged();
notifyObservers(ChangedValue.ID);//use the enum types as parameters here
}
public void setName(String name) {
this.name = name;
setChanged();
notifyObservers(ChangedValue.NAME);
}
public void setEmail(String email) {
this.name = email;
setChanged();
notifyObservers(ChangedValue.EMAIL);
}
}
注意: 如评论中所述,通用方法会更好,以避免对象强制转换。它可以与此实现类似地使用。只是加了一些泛型参数,思路还是一样的。
我的意思是这样的:
public class UserModel extends Observable {
enum AttributeKind {
ID, NAME, EMAIL;
}
class UserModelDescriptor {
public AttributeKind attributeKind;
public Object attribute;
public UserModelDescriptor(AttributeKind attributeKind, Object attribute) {
super();
this.attributeKind = attributeKind;
this.attribute = attribute;
}
}
private Integer id;
private String name;
private String email;
/* getters */
public void setId(Integer id){
this.id = id;
setChanged();
notifyObservers(new UserModelDescriptor(AttributeKind.ID, id));
}
. . .
}
观察者:
public class UserBean implements Observer{
@Override
public void update(Observable o, Object arg) {
UserModelDescriptor descriptor = (UserModelDescriptor)arg;
switch (descriptor.attributeKind) {
case ID:
int id = (Integer)descriptor.attribute;
break;
. . .
}
}
}
...但是基于 PropertyChangeListener class 的方法要好得多。
我在 MVC 应用程序中实现了观察者模式,因此 bean 可以侦听模型中的更改。因为我在 Java8,所以我使用 Java.util 的 Observer 和 Observable。这是我编码的部分内容:
import java.util.Observable;
import java.util.Observer;
public class UserBean implements Observer{
private Integer userId;
private String userName;
private String userEmail;
/* getters and setters */
@Override
public void update(Observable o, Object object) {
if(object instanceof Integer)
setUserId((Integer)object);
else if(object instanceof String)
setUserName((String)object);
}
}
public class UserModel extends Observable {
private Integer id;
private String name;
private String email;
/* getters */
public void setId(Integer id){
this.id = id;
setChanged();
notifyObservers(id);
}
public void setName(String name){
this.name = name;
setChanged();
notifyObservers(name);
}
public void setEmail(String email){
this.name = email;
// how can i listen for this change?
/*setChanged();
notifyObservers(email);*/
}
}
我认为实现是正确的,因为在我进行的简单测试中,bean 正确读取了 ID 和名称的更改 class,但我意识到我无法监听更改电子邮件属性,因为在 bean class 中,我使用 'instanceof' 来了解我必须更新哪个值。
有什么方法可以识别哪个变量发生了变化?我应该实现自己的 Observer 和 Observable class 版本而不是使用 Java.Util? 我认为使用第二种解决方案我可以为每个属性定义一个更新方法,但我不知道如何在 Java.
中管理同步过程update
方法中的第一个参数是 Observable
。那是您的 UserModel
对象发生了变化,因此它包含所有更新的数据。因此,与其使用第二个参数来传递对象的新 value,不如使用它来传递已更改对象的 name (或使用 enum
因为它有点 cleaner).
解决方案可能如下所示:
UserBean:
import java.util.Observable;
import java.util.Observer;
import observer.UserModel.ChangedValue;
public class UserBean implements Observer {
private Integer userId;
private String userName;
private String userEmail;
/* getters and setters */
@Override
public void update(Observable o, Object object) {
if (o instanceof UserModel && object instanceof ChangedValue) {
UserModel userModel = (UserModel) o;
ChangedValue changed = (ChangedValue) object;
switch (changed) {
case EMAIL:
setEmail(userModel.getEmail());
break;
case ID:
setUserId(userModel.getId());
break;
case NAME:
setUserName(userModel.getName());
break;
default:
throw new IllegalStateException("Unexpected ChangedValue type: " + changed);
}
}
}
//...
}
用户模型:
import java.util.Observable;
public class UserModel extends Observable {
public enum ChangedValue {
ID, //
NAME, //
EMAIL, //
//...
}
private Integer id;
private String name;
private String email;
//...
public void setId(Integer id) {
this.id = id;
setChanged();
notifyObservers(ChangedValue.ID);//use the enum types as parameters here
}
public void setName(String name) {
this.name = name;
setChanged();
notifyObservers(ChangedValue.NAME);
}
public void setEmail(String email) {
this.name = email;
setChanged();
notifyObservers(ChangedValue.EMAIL);
}
}
注意: 如评论中所述,通用方法会更好,以避免对象强制转换。它可以与此实现类似地使用。只是加了一些泛型参数,思路还是一样的。
我的意思是这样的:
public class UserModel extends Observable {
enum AttributeKind {
ID, NAME, EMAIL;
}
class UserModelDescriptor {
public AttributeKind attributeKind;
public Object attribute;
public UserModelDescriptor(AttributeKind attributeKind, Object attribute) {
super();
this.attributeKind = attributeKind;
this.attribute = attribute;
}
}
private Integer id;
private String name;
private String email;
/* getters */
public void setId(Integer id){
this.id = id;
setChanged();
notifyObservers(new UserModelDescriptor(AttributeKind.ID, id));
}
. . .
}
观察者:
public class UserBean implements Observer{
@Override
public void update(Observable o, Object arg) {
UserModelDescriptor descriptor = (UserModelDescriptor)arg;
switch (descriptor.attributeKind) {
case ID:
int id = (Integer)descriptor.attribute;
break;
. . .
}
}
}
...但是基于 PropertyChangeListener class 的方法要好得多。