如何将可重用的多步状态机实现到 MVP 中?
How to implement a reusable multistep state-machine into MVP?
在我的 Android 应用程序中,我有一个多步骤登录程序:
- 输入一个id,发送到后端:
firstCall(id)
- 如果没有找到id,请求correct/another id
- 如果 id 正确,继续步骤 2。
- 输入密码并将(散列)发送到后端
secondCall(password)
- 如果密码错误,请重新请求(受限)
- 如果密码正确,继续 3。
- 后端响应此会话的时间限制令牌 (sessionToken)
- 用这个令牌做一件事
1 有 wrongId()
和 correctId()
个回调。
有 wrongPassword()
和 correctPassword()
回调 2.
我已经通过使用 MVP 模式在我的 Android 应用程序中成功实现了这一点。
由于我在不同的活动(全部在 MVP 中)上使用了这个登录过程,所以我有很多重复的代码。我将此登录名提取到一个单独的 class,在演示者中仍会使用它。但是后来我遇到了请求错误密码的问题?
我是否需要在所有演示者中实施回调?
我如何通知当前使用的演示者密码错误等?
有多种方法可以做到这一点,但实施会受到多种因素的影响。对于您的案例的更具体示例,您需要提供有关系统及其要求的更多信息。一些示例代码也会有所帮助。
- 如果您需要从多个地方登录,每个地方的视图是否不同?
- 登录过程有什么不同,所有登录是相同的还是不同的?
实现此目的的一种方法是为所有支持登录的演示者使用基础 class。这是一个简化的示例(为简单起见,我将跳过对无效输入的检查和重试,您还必须提供更多详细信息和示例代码,以便给出适合您情况的更详细示例 ):
public interface Api {
bool isIdValid(UUID id);
Token getToken(UUID id, string password);
}
public interface LoginView {
UUID askUserForId();
string askUserForPassword();
void notifyForInvalidId();
void notifyForInvalidPassword();
void showNoMorePasswordAttemptsAllowed();
}
public class LoginPresenterBase {
private Api mApi;
private LoginView mLoginView;
public LoginPresenterBase(LoginView loginView, Api api, other stuff){
mApi = api;
mLoginView = loginView;
}
public Token doLogin() {
UUID id = null;
while(true) {
id = mLoginView.askUserForId();
// add end condition here so you don't cycle forever when the user clicks
a cancel button or whatever
if(!mApi.isIdValid(id)) {
mLoginView.notifyForInvalidId();
}
else {
break;
}
}
for(int i = 0; i < retriesCount; ++i) {
stirng password = mLoginView.askUserForPassword();
// exit if the user clicks a cancel button or closes the dialog.
Token token = null;
try {
token = mApi.getToken(id, password);
}
catch(InvalidPasswordException) {
if(i == retriesCount - 1){
// if last retry
mLoginView.showNoMorePasswordAttemptsAllowed();
}
else {
mLoginView.notifyForInvalidPassword();
}
}
return token;
}
}
}
另一种方法是创建一个登录进程来表示步骤顺序。由于此过程需要从外部提供一些数据(例如密码)(例如用户在 UI window 中输入),您可以使用接口或回调从您的 登录过程 供某人提供所需数据。
通过这种方式,您可以 plug-in 不同的视图 and/or 演示者添加特定逻辑(例如密码输入)并重用流程。
这是一个例子:
public interace IdProvider {
public UUID getId();
public void invalidIdProvided(UUID);
}
public interface PasswordProvider {
public string getPassword();
public void invalidPasswordProvided(string password);
public void maxPasswordAttemptsReached();
}
public class LoginProcess {
private Api mApi;
private IdProvider mIdProvider;
private PasswordProvider mPasswordProvider;
public LoginProcess(
IdProvider idProvider, PasswordProvider passwordProvider, Api api) {
mApi = api;
mIdProvider = idProvider;
mPasswordProvider = passwordProvider;
}
public Token execute() {
UUID id = null;
while(true) {
id = mIdProvider.getId();
if(!mApi.isIdValid(id)) {
mIdProvider.invalidIdProvided(id);
// add end condition here so you don't cycle forever when the
// user clicks a cancel button or whatever
}
else {
break;
}
}
for(int i = 0; i < retriesCount; ++i) {
string password = mPasswordProvider.getPassword();
Token token = null;
try {
token = mApi.getToken(id, password);
}
catch(InvalidPasswordException) {
if(i == retriesCount - 1){
// if last retry
mPasswordProvider.maxPasswordAttemptsReached();
}
else {
mPasswordProvider.invalidPasswordProvided();
}
}
return token;
}
}
这样你就可以 plug-in 每 view/presenter 你不想。只需实现接口,流程就会在一个单独的对象中。如有必要,您可以创建一个实现接口的基本演示器。
带有 LoginProcess class 的最后一个解决方案具有最好的 Separation of Concerns and uses the Single Responsibility Principle.
它的问题是您必须定义另一组接口和 classes.
第一个使用较少的代码并且仍然有效。您可以重用演示者,您可以创建一个实现 LoginView 接口的视图,您可以重用或用作基础 class .
在我的 Android 应用程序中,我有一个多步骤登录程序:
- 输入一个id,发送到后端:
firstCall(id)
- 如果没有找到id,请求correct/another id
- 如果 id 正确,继续步骤 2。
- 输入密码并将(散列)发送到后端
secondCall(password)
- 如果密码错误,请重新请求(受限)
- 如果密码正确,继续 3。
- 后端响应此会话的时间限制令牌 (sessionToken)
- 用这个令牌做一件事
1 有 wrongId()
和 correctId()
个回调。
有 wrongPassword()
和 correctPassword()
回调 2.
我已经通过使用 MVP 模式在我的 Android 应用程序中成功实现了这一点。
由于我在不同的活动(全部在 MVP 中)上使用了这个登录过程,所以我有很多重复的代码。我将此登录名提取到一个单独的 class,在演示者中仍会使用它。但是后来我遇到了请求错误密码的问题?
我是否需要在所有演示者中实施回调? 我如何通知当前使用的演示者密码错误等?
有多种方法可以做到这一点,但实施会受到多种因素的影响。对于您的案例的更具体示例,您需要提供有关系统及其要求的更多信息。一些示例代码也会有所帮助。
- 如果您需要从多个地方登录,每个地方的视图是否不同?
- 登录过程有什么不同,所有登录是相同的还是不同的?
实现此目的的一种方法是为所有支持登录的演示者使用基础 class。这是一个简化的示例(为简单起见,我将跳过对无效输入的检查和重试,您还必须提供更多详细信息和示例代码,以便给出适合您情况的更详细示例 ):
public interface Api {
bool isIdValid(UUID id);
Token getToken(UUID id, string password);
}
public interface LoginView {
UUID askUserForId();
string askUserForPassword();
void notifyForInvalidId();
void notifyForInvalidPassword();
void showNoMorePasswordAttemptsAllowed();
}
public class LoginPresenterBase {
private Api mApi;
private LoginView mLoginView;
public LoginPresenterBase(LoginView loginView, Api api, other stuff){
mApi = api;
mLoginView = loginView;
}
public Token doLogin() {
UUID id = null;
while(true) {
id = mLoginView.askUserForId();
// add end condition here so you don't cycle forever when the user clicks
a cancel button or whatever
if(!mApi.isIdValid(id)) {
mLoginView.notifyForInvalidId();
}
else {
break;
}
}
for(int i = 0; i < retriesCount; ++i) {
stirng password = mLoginView.askUserForPassword();
// exit if the user clicks a cancel button or closes the dialog.
Token token = null;
try {
token = mApi.getToken(id, password);
}
catch(InvalidPasswordException) {
if(i == retriesCount - 1){
// if last retry
mLoginView.showNoMorePasswordAttemptsAllowed();
}
else {
mLoginView.notifyForInvalidPassword();
}
}
return token;
}
}
}
另一种方法是创建一个登录进程来表示步骤顺序。由于此过程需要从外部提供一些数据(例如密码)(例如用户在 UI window 中输入),您可以使用接口或回调从您的 登录过程 供某人提供所需数据。
通过这种方式,您可以 plug-in 不同的视图 and/or 演示者添加特定逻辑(例如密码输入)并重用流程。
这是一个例子:
public interace IdProvider {
public UUID getId();
public void invalidIdProvided(UUID);
}
public interface PasswordProvider {
public string getPassword();
public void invalidPasswordProvided(string password);
public void maxPasswordAttemptsReached();
}
public class LoginProcess {
private Api mApi;
private IdProvider mIdProvider;
private PasswordProvider mPasswordProvider;
public LoginProcess(
IdProvider idProvider, PasswordProvider passwordProvider, Api api) {
mApi = api;
mIdProvider = idProvider;
mPasswordProvider = passwordProvider;
}
public Token execute() {
UUID id = null;
while(true) {
id = mIdProvider.getId();
if(!mApi.isIdValid(id)) {
mIdProvider.invalidIdProvided(id);
// add end condition here so you don't cycle forever when the
// user clicks a cancel button or whatever
}
else {
break;
}
}
for(int i = 0; i < retriesCount; ++i) {
string password = mPasswordProvider.getPassword();
Token token = null;
try {
token = mApi.getToken(id, password);
}
catch(InvalidPasswordException) {
if(i == retriesCount - 1){
// if last retry
mPasswordProvider.maxPasswordAttemptsReached();
}
else {
mPasswordProvider.invalidPasswordProvided();
}
}
return token;
}
}
这样你就可以 plug-in 每 view/presenter 你不想。只需实现接口,流程就会在一个单独的对象中。如有必要,您可以创建一个实现接口的基本演示器。
带有 LoginProcess class 的最后一个解决方案具有最好的 Separation of Concerns and uses the Single Responsibility Principle.
它的问题是您必须定义另一组接口和 classes.
第一个使用较少的代码并且仍然有效。您可以重用演示者,您可以创建一个实现 LoginView 接口的视图,您可以重用或用作基础 class .