【问题标题】:How to observe different attributes of same types with the Observer pattern?如何用观察者模式观察同一类型的不同属性?
【发布时间】:2020-12-26 15:42:40
【问题描述】:

我在 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 类正确读取了对 Ids 和 Names 的更改,但我意识到我无法监听电子邮件属性的更改,因为在我正在使用 'instanceof' 来了解我必须更新哪个值的 bean 类。

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

【问题讨论】:

  • 你也可以使用 DTO 通知观察者,它会带来一些关于属性的额外信息
  • 不要使用 j.u.Observer 和 Observable。它们已经非常过时了。一个合适的接口定义应该使用泛型;它们是在泛型存在之前编写的。
  • 遵循@Michael 的建议:stackoverflow.com/questions/46380073/…
  • @fantaghirocco 哦,很好。我几乎在我上次的评论中说他们应该继续并弃用它。很高兴他们有。那个从我身边经过:)
  • @fantaghirocco 你能解释得更好吗?我的教授没有向我们解释所有现有的模式,我也不知道 DTO(我只是用谷歌搜索)。

标签: java observer-pattern


【解决方案1】:

我的意思是这样的:

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

【讨论】:

  • 哦,很好,我明白你在这里做了什么。当我必须将复杂数据发送到线程时,我通常在 C 编程中做这样的事情。我认为这应该可以,我会试一试!
  • 这不是很好,但有可能:是的,类的用法以某种方式提醒了一个 C 结构
【解决方案2】:

update 方法中的第一个参数是Observable。那是您的 UserModel 对象已更改,因此它包含所有更新的数据。因此,与其使用第二个参数来传递对象的新 value,不如使用它来传递已更改对象的 name(或使用enum因为它有点更干净)。

解决方案可能如下所示:

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

注意:就像在 cmets 中提到的那样,通用方法会更好,以避免对象强制转换。它可以与此实现类似地使用。只需添加一些泛型参数,但思路不变。

【讨论】:

  • 您的方法更简洁,因为不涉及额外的类。赞成
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-05-11
  • 2013-12-03
  • 1970-01-01
  • 1970-01-01
  • 2016-02-20
  • 2023-04-10
  • 2013-02-12
相关资源
最近更新 更多