在MVC设计中存储模型对象的位置?

时间:2018-03-11 23:07:53

标签: java model-view-controller fxml

我正在使用MVC架构。

SignupController从SignupView创建一个User对象。

该用户应存放在哪里?

我已经尝试将其存储到MainController中,但是当我需要访问User对象时,我需要再次初始化MainController,因此User现在为null。

谢谢!

2 个答案:

答案 0 :(得分:1)

好的,让我们后退一步。 User是数据,在此内容中,数据应由模型层管理和维护。

控制器负责协调视图和模型之间的操作和通知。在这个意义上,当用户在视图中触发请求(即执行注册操作)时,视图会触发控制器订阅的事件。控制器从视图中获取所需信息并将该信息传递给模型。这可能会向后工作,模型会根据任务的成功触发事件,控制器会根据需要通知视图

这一切的重要部分,是没有人知道其他部分是如何运作的......并且不关心

让我们从基础开始。您需要某种方式来表示"用户"

public interface User {
    public String getName();
}

现在,您需要创建一个User ...

public interface UserFactoryListener {
    public void userCreated(User user);
    public void userCreationFailed(Exception exp); // Or some other error object
}

public interface UserFactory {
    public void makeUser(String name);

    public void addUserFactoryListener(UserFactoryListener listener);
    public void removeUserFactoryListener(UserFactoryListener listener);
}

所以,这是一个工厂的基本概念,它将取用户的名字并创建一个新的User对象,这里需要注意的重要一点是,我们不在乎&#34 ;如何"完成后,只有这样做,并且它将生成成功或失败事件

但是,如果我们还希望能够对用户进行身份验证呢?

public interface UserAuthenticationistener {
    public void userAuthenticated(User user);
    public void userAuthenticationFailed(Exception exp); // Or some other error object
}

public interface UserAuthenticator {
    public void authenticateUser(String name, char[] password) throws SecurityException;

    public void addUserAuthenticator(UserAuthenticator listener);
    public void removeUserAuthenticator(UserAuthenticator listener);
}

所以,这是一个基本的想法,它需要一个名称和密码,并在某种程度上验证用户,我们不关心,并将产生我们可以订阅的成功或失败事件。 / p>

"是的,但用户模型怎么样?" 我听到你说,很高兴你问过!

public interface UserSigninModel extends UserFactory, UserAuthenticator {

}

嗯,好吧,这是登录模型,但它包含了我们想要支持,注册或登录的两个主要功能。

现在,我们需要一些方法来协调两者,这是控制器的工作......

public interface UserSigninController extends UserSigninViewListener, UserFactoryListener, UserAuthenticationistener {
    public UserSigninModel getModel();
    public UserSigninView getView();
}

......好吧,这有点令人印象深刻,但这就是重点

最后,我们需要一些方法来与实际用户进行交互,即视图!

public interface UserSigninViewListener {
    public void signupUser(UserSigninView view);
    public void authenticateUser(UserSigninView view);
}

public interface UserSigninView {
    public Pane getView();

    public String getName();
    public char[] getPassword();

    public void addUserSigninViewListener(UserSigninViewListener listener);
    public void removeUserSigninViewListener(UserSigninViewListener listener);

    public void userSignupFailed(Exception exp);
    public void userAuthenticationFailed(Exception exp);
}

所以,所有这一切都做了一件简单的工作。它描述了每个层预期提供的意图(或合同)。任何一方都没有真正关心其他部分是如何实施的,只是合同得到维护

例如,可能的控制器实现看起来像......

public class DefaultUserSigninController implements UserSigninController {
    private UserSigninModel model;
    private UserSigninView view;

    public DefaultUserSigninController(UserSigninModel model, UserSigninView view) {
        this.model = model;
        this.view = view;
    }

    @Override
    public UserSigninModel getModel() {
        return model;
    }

    @Override
    public UserSigninView getView() {
        return view;
    }

    @Override
    public void signupUser(UserSigninView view) {
        getModel().makeUser(view.getName());
    }

    @Override
    public void authenticateUser(UserSigninView view) {
        getModel().authenticateUser(view.getName(), view.getPassword());
    }

    @Override
    public void userCreated(User user) {
        // Coordinate with the navigation controller to move to the
        // next part of the program. This might pass the User object
        // to the navigation controller (as a event) so it
        // can be seeded into the next model
    }

    @Override
    public void userCreationFailed(Exception exp) {
        getView().userSignupFailed(exp);
    }

    @Override
    public void userAuthenticated(User user) {
        // Coordinate with the navigation controller to move to the
        // next part of the program. This might pass the User object
        // to the navigation controller (as a event) so it
        // can be seeded into the next model
    }

    @Override
    public void userAuthenticationFailed(Exception exp) {
        getView().userAuthenticationFailed(exp);
    }

}

控制器本身并没有做很多事情,除此之外协调视图和模型之间的通信。它还提供了向另一个"导航控制器提供通知的可能性。可能负责确定下一个应显示哪个控制器/视图。它甚至可能创建" base"模型包装新的User对象。

声明

这是一个过于简化的例子,旨在提供一个可证明的工作流程概念 - 重点是,"如何"并不重要,因为它应该隐藏在interface之后,每个层同意实施的合同至关重要。

此外,我的JavaFX很小,因此可以更改事件管理以更好地适应API实际如何实现它的可观察模式

答案 1 :(得分:0)

据我所知,基于fxml标记,您正在使用Java FX构建应用程序,这意味着应用程序中任何时候只有一个User。在这种情况下,最好的方法是将其存储在一个单独的类中,如服务或存储库。

示例:

public class UserService {

    protected User user;

    public Optional<User> getUser() {
        return Optional.ofNullable(user);
    }

    public void setUser(User user) {
        this.user = user;
    }

}

然后使用Dependency Injection(例如Guice)或某种Singleton Pattern实施,例如getInstance()

如果您正在讨论Web应用程序,我建议在会话中保留引用,因为这会将User绑定到执行HTTP请求的实际用户。