【问题标题】:Listen when something changes and update it to database监听发生变化并将其更新到数据库
【发布时间】:2017-09-23 21:53:32
【问题描述】:

所以我正在开发一个使用 mongodb/morphia 的软件,我需要一种方法来监听该对象,以检查某个值何时更改以在数据库中更新它,而不是手动进行。

最好的方法是什么?观察者模式?

所以我有 3 个类:User(超类)、GlobalPlayer 和我的 Main。 我知道我需要使用观察者模式,但我在实施时遇到了问题。

用户等级:

GlobalPlayer 类:

主类:

正如您在我的主类中看到的那样,我每 5 秒更新一次 GlobalPlayer,即使它没有任何新的更新,那么我该如何在其中实现观察者模式?

【问题讨论】:

  • 我建议将您的标题更改为更具体的内容,并在您的问题正文中添加更多信息。
  • @clabe45 好的,看看现在好些了吗。

标签: java mongodb task future morphia


【解决方案1】:

使用脏标志。

使用观察者模式,您可以跟踪每个更改。但是,您真的想在每次进行一点更改时都保存每个用户吗?可能不会,所以在使用观察者时,您可能还想构建一些东西,通过延迟写入来防止数据库负载过高。此外,我总是尽量保持我的 Dataobjects 简单,连接松散,因为这样可以降低复杂性。因此,我的猜测是观察者模式太过分了,并且比需要的更复杂。只需使用脏位和计划任务来定期保存每个用户。在系统崩溃的情况下,负载不大,只有少量数据丢失。

public class User {

  @Transient
  boolean dirty;

  private void markDirty() {
    dirty = true;
  }

  public void isDirty {
    return dirty();
  }

每个setter,都应该先调用markDirty()方法。像这样:

public void addCoins(long coins) {
  markDirty();
  this.coins += coins;
}

而在 Global 中,我们只在他/她/它/其他脏的时候才保存用户:

if (gp.isDirty()) {
  getPlayerManager().update(gp);
}

更好的设计是将 if(gp.isDirty()) 移动到 PlayerManager 类的 update,因为保存时间应该是 Playermanager 的责任。

【讨论】:

    【解决方案2】:

    正如 jjohns 所指出的,您可以使用 Observers 和 Observables

    编辑

    他可能不是那个意思。 从 Java 9 开始,这种观察者模式已被弃用。 一种替代方法是声明您自己的事件,该事件是 EventObject 的子类:

    class UserChangeEvent extends EventObject {
        private String actionCommand;  // additional property for more control
        public UserChangeEvent(Object source, String actionCommand) {
            super(source);
            this.actionCommand = actionCommand;
        }
        public String getActionCommand() { return actionCommand; }
    }
    

    然后,声明一个将处理事件的接口(@98​​7654329@ 将是“回调”方法):

    interface UserChangeListener {
        /**
         * Fired when any user property changes
         * @param event
         */
        public void onUserChange(UserChangeEvent event);
    }
    

    这是User 类的示例:

    class User {
        private List<UserChangeListener> changeListeners = new ArrayList<UserChangeListener>();
        private String username;
        private String email;
        
        public User(String username, String email) {
            this.username = username;
            this.email = email;
        }
        /**
         * Registers a UserChangeListener instance that will be notified when any setter is called
         * @param listener the new event listener
         */
        public void addUserChangeListener(UserChangeListener listener) {
            changeListeners.add(listener);
        }
        public String getUsername() { 
            return username; 
        }
        public void setUsername(String username) { 
            this.username = username;  // actually set the username
            UserChangeEvent event = new UserChangeEvent(this, "username");  // a new instance of our custom user change event
            // fire user change event for all event listeners
            for (UserChangeListener listener:changeListeners) {
                listener.onUserChange(event);
            }
        }
        public String getEmail() { 
            return email; 
        }
        public void setEmail(String email) { 
            this.email = email; 
            UserChangeEvent event = new UserChangeEvent(this, "email");
            for (UserChangeListener listener:changeListeners) {
                listener.onUserChange(event);
            }
        }   
    }
    

    这是User、UserChangeEvent和UserChangeListener的简单实现:

    public class Test {
        public static void main(String[] args) {
            User hworld1234 = new User("hworld1234", "hworld@example.com");
            hworld1234.addUserChangeListener(new UserChangeListener() {
                
                @Override
                public void onUserChange(UserChangeEvent event) {
                    String actionCommand = event.getActionCommand();  // what we gave our custom event in the setters
                    if ("username".equals(actionCommand)) {
                        System.out.println("username has been changed to '" + hworld1234.getUsername() + "'");
                    } else if ("email".equals(actionCommand)) {
                        System.out.println("email has been changed to '" + hworld1234.getEmail() + "'");
                    }
                }
            });
            hworld1234.setEmail("hworld@gmail.com");  // prints "email has been changed to 'hworld@gmail.com'"
    
        }   
    }
    

    如果您愿意,另一种方法是为要“绑定”的每个属性声明一个 onXXXChange 并忘记 actionCommand 属性;不过,如果你在一个接口中甚至有多个方法,你可能应该把它变成一个适配器。

    【讨论】:

    • 这是 observable/observer 模式的一个非常糟糕的实现版本。
    • @jjones 怎么样?我该如何改进?
    • 这是一个简单实现的UML类和序列图:upload.wikimedia.org/wikipedia/commons/0/01/…
    • 您的课程仅限于单一效果,并且需要了解如何执行该效果。
    • @jjones 我要看看那个观察者模式,谢谢:D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-05-26
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 2020-12-30
    • 2022-10-24
    相关资源
    最近更新 更多