如何使用观察者模式观察相同类型的不同属性?

时间:2020-09-08 09:12:46

标签: java observer-pattern

我在MVC应用程序中实现了Observer模式,因此Bean可以侦听模型中的更改。因为我在Java8中,所以我使用的是Observer和Java.util中的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类正确读取了对Ids和Names的更改,但是我意识到我听不到电子邮件属性的更改,因为在我正在使用'instanceof'的bean类来了解我必须更新哪个值。

有一种方法可以识别哪个变量已更改?我应该实现自己的Observer和Observable类版本,而不是使用Java.Util? 我认为使用第二种解决方案可以为每个属性定义一个更新方法,但是我不知道如何在Java中管理同步过程。

2 个答案:

答案 0 :(得分:2)

update方法中的第一个参数是Observable。那是您的UserModel对象已更改,因此它包含所有更新的数据。因此,与其使用第二个参数传递对象的新,您可以使用它传递已更改对象的 name (或使用{{1 }},因为它有点 cleaner )。

解决方案如下:

UserBean:

enum

用户模型:

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);
                
            }
        }
    }
    
    //...
}

注意:就像注释中提到的那样,通用方法会更好,以避免对象强制转换。可以类似于此实现方式使用。只需添加一些通用参数,但是想法保持不变。

答案 1 :(得分:2)

我的意思是这样的:

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类的方法要好得多。