MVC设计中模型对象存放在哪里?
Where to store model objects in MVC design?
我正在使用 MVC 架构。
SignupController 从 SignupView 创建一个 User 对象。
这个用户应该存储在哪里?
我试过将其存储到 MainController 中,但是当我需要访问 User 对象时,我需要再次初始化 MainController,因此 User 现在为 null。
谢谢!
据我了解,基于 fxml
标记,您正在使用 Java FX 构建应用程序,这意味着在任何时候都只有一个 User
应用程序。在这种情况下,最好的方法是将其存储在单独的 class 中,例如服务或存储库。
示例:
public class UserService {
protected User user;
public Optional<User> getUser() {
return Optional.ofNullable(user);
}
public void setUser(User user) {
this.user = user;
}
}
然后要么使用 Dependency Injection (e.g. Guice) or some sort of a Singleton Pattern 实现,例如getInstance()
.
如果您谈论的是 Web 应用程序,我建议在会话中保留引用,因为这会将 User
绑定到执行 HTTP 请求的实际用户。
好吧,让我们退一步。 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
对象,这里要注意的重要一点是,我们不关心“如何”完成了,只有完成了,它会生成成功或失败事件
但是,如果我们还希望能够对用户进行身份验证怎么办?
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);
}
所以,这是相同的基本思想,它需要一个名称和密码并以某种方式验证用户,我们不关心,并将生成一个我们可以订阅的成功或失败事件。
“是的,但是用户模型呢?”我听到你说,很高兴你问!
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);
}
}
控制器本身并没有做很多事情,除了协调视图和模型之间的通信。它还提供了向另一个“导航控制器”提供通知的可能性,该控制器可能负责确定接下来应该显示哪个 controller/view。它甚至可能创建包含新 User
对象的“基础”模型。
免责声明
这是一个过于简化的示例,旨在提供一个可证明的工作流程概念 - 重点是,“如何”并不重要,因为它应该全部隐藏在 interface
之后,重要的是是每一层同意执行的契约。
此外,我的 JavaFX 是最小的,因此可以更改事件管理以更好地适应 API 实际实现其可观察模式的方式
我正在使用 MVC 架构。
SignupController 从 SignupView 创建一个 User 对象。
这个用户应该存储在哪里?
我试过将其存储到 MainController 中,但是当我需要访问 User 对象时,我需要再次初始化 MainController,因此 User 现在为 null。
谢谢!
据我了解,基于 fxml
标记,您正在使用 Java FX 构建应用程序,这意味着在任何时候都只有一个 User
应用程序。在这种情况下,最好的方法是将其存储在单独的 class 中,例如服务或存储库。
示例:
public class UserService {
protected User user;
public Optional<User> getUser() {
return Optional.ofNullable(user);
}
public void setUser(User user) {
this.user = user;
}
}
然后要么使用 Dependency Injection (e.g. Guice) or some sort of a Singleton Pattern 实现,例如getInstance()
.
如果您谈论的是 Web 应用程序,我建议在会话中保留引用,因为这会将 User
绑定到执行 HTTP 请求的实际用户。
好吧,让我们退一步。 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
对象,这里要注意的重要一点是,我们不关心“如何”完成了,只有完成了,它会生成成功或失败事件
但是,如果我们还希望能够对用户进行身份验证怎么办?
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);
}
所以,这是相同的基本思想,它需要一个名称和密码并以某种方式验证用户,我们不关心,并将生成一个我们可以订阅的成功或失败事件。
“是的,但是用户模型呢?”我听到你说,很高兴你问!
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);
}
}
控制器本身并没有做很多事情,除了协调视图和模型之间的通信。它还提供了向另一个“导航控制器”提供通知的可能性,该控制器可能负责确定接下来应该显示哪个 controller/view。它甚至可能创建包含新 User
对象的“基础”模型。
免责声明
这是一个过于简化的示例,旨在提供一个可证明的工作流程概念 - 重点是,“如何”并不重要,因为它应该全部隐藏在 interface
之后,重要的是是每一层同意执行的契约。
此外,我的 JavaFX 是最小的,因此可以更改事件管理以更好地适应 API 实际实现其可观察模式的方式